perm filename ARMSOL.PAL[AL,HE]15 blob
sn#605452 filedate 1981-08-13 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00058 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00006 00002 ARMSOL - SUITE OF PROGRAMS INVOLVING ARM KINEMATICS
C00009 00003 DEFINITIONS FOR USING THE MATRICES AND VECTORS:
C00011 00004 ---> SOLVE <--- THE STANFORD ARM SOLUTION
C00014 00005 ["SOLVE" - CHECK IF ARM OR HAND]
C00018 00006 ["SOLVE" - JOINT 1]
C00021 00007 ["SOLVE" - JOINTS 2 & 3]
C00023 00008 ["SOLVE" - JOINT 5]
C00026 00009 ["SOLVE" - DEGENERATE SOLUTION AND JOINT 4]
C00030 00010 ["SOLVE" - JOINT 6]
C00033 00011 ["SOLVE" LOCAL STORAGE AREA]
C00035 00012 ---> PUMSOL <--- THE PUMA ARM SOLUTION
C00046 00013 ["PUMSOL" - THE MAIN PART]
C00052 00014 ["PUMSOL" - GETSOL]
C00057 00015 ["PUMSOL" - SSETUP]
C00061 00016 ["PUMSOL" - ROTATION ROUTINES]
C00064 00017 ["PUMSOL" - FINDS]
C00069 00018 ["PUMSOL" - GET1]
C00074 00019 ["PUMSOL" - GET3]
C00078 00020 ["PUMSOL" - GET2]
C00082 00021 ["PUMSOL" - GET4]
C00084 00022 ["PUMSOL" - GET5]
C00086 00023 ["PUMSOL" - GET6]
C00089 00024 ["PUMSOL" - FIX4]
C00092 00025 ["PUMSOL" - OFSETS]
C00094 00026 ["PUMSOL" - ANGLE MANIPULATION ROUTINES]
C00098 00027 ["PUMSOL" - VECTOR MANIPULATION ROUTINES]
C00102 00028 ["PUMSOL" - LOCAL DATA]
C00104 00029 UPDATE - COMPUTES THE ARM TRANSFORM GIVEN THE JOINT ANGLES
C00110 00030 ["UPDATE"- HAND OR T6]
C00113 00031 ---> PUMUPD < --- THE PUMA UPDATE ROUTINE
C00119 00032 [CONTINUATION OF PUMUPD: THE MAIN PART]
C00120 00033 [CONTINUATION OF PUMUPD: DOTRIG]
C00122 00034 [CONTINUATION OF PUMUPD: GETN]
C00124 00035 [CONTINUATION OF PUMUPD: GETO]
C00126 00036 [CONTINUATION OF PUMUPD: GETA]
C00128 00037 [CONTINUATION OF PUMUPD: GETP]
C00130 00038 [CONTINUATION OF PUMUPD: GETXY]
C00131 00039 [CONTINUATION OF PUMUPD: OFSETW]
C00134 00040 [CONTINUATION OF PUMUPD: LOCAL DATA AND CONSTANTS]
C00135 00041 JACOB - COMPUTES JACOBIAN MATRIX
C00136 00042 ["JACOB" - FORM CT0,CT3,CT6]
C00139 00043 ["JACOB" - POSITION VECTORS, AXES OF ROTATION]
C00142 00044 ["JACOB" - CROSS PRODUCTS, CLEAN UP]
C00144 00045 T0336 - COMPUTES TRANSFORMATION MATRICIES FOR JTS 1-3 AND 4-6
C00147 00046 T6330 - COMPUTES TRANSFORMATION MATRICIES FOR JTS 6-4 AND 3-0
C00149 00047 R03 - COMPUTES ROTATION MATRIX FOR TRANSFORMATION FROM JTS 1-3
C00151 00048 R36 - COMPUTES ROTATION MATRIX FOR TRANSFORMATION FROM JTS 4-6
C00154 00049 INVERT - INVERTS A TRANSFORMATION STORED BY COLUMNS
C00155 00050 MATMUL - PERFORMS THE OPERATION T0 ← T1*T2
C00158 00051 MULT - PERFORMS THE OPERATION A0 ← A1*A2
C00160 00052 CROSS - VECTOR CROSS PRODUCT OPERATION V0 ← V1 X V2
C00162 00053 LOCAL STORAGE AREA
C00164 00054 PHYSICAL CONSTANTS FOR YELLOW AND BLUE ARMS
C00165 00055 [YELLOW ARM TABLE OF CONSTANTS]
C00166 00056 [BLUE ARM TABLE OF CONSTANTS]
C00167 00057 [GREEN & RED ARM TABLE OF CONSTANTS]
C00168 00058 PUMA CONSTANTS AND MISC. DATA FOR PUMA ROUTINES
C00171 ENDMK
C⊗;
;ARMSOL - SUITE OF PROGRAMS INVOLVING ARM KINEMATICS
.TITLE ARMSOL
;THE FOLLOWING PROGRAMS ARE USED TO COMPUTE THE JOINT ANGLES FOR THE
;SCHEINMAN MANIPULATORS GIVEN A REQUIRED TRANSFORM OR VISE VERSA.
;ALSO INCLUDED IS A PROGRAM FOR COMPUTING THE REACTION TORQUES AT THE
;JOINTS FOR A GIVEN FORCE AND MOMENT COUPLE AT THE HAND.
;THE THEORETICAL BASIS FOR THE KINEMATIC SOLUTIONS IMPLEMENTED IN
;THESE PROGRAMS IS PRESENTED IN STANFORD ARTIFICIAL INTELLIGENCE
;LABORATORY HAND/EYE GROUP PROGRESS REPORT, DEC 1975 THRU JULY 1976.
;WHEREVER POSSIBLE, THE VARIABLE NAMES USED IN THAT DOCUMENT AND IN
;THE FOLLOWING PROGRAMS ARE THE SAME.
;THE FOLLOWING MECHANISM BITS INDICATE WHICH PHYSICAL DEVICE IS BEING
;USED:
YELARM ==1 ;YELLOW ARM, NOT INCLUDING HAND
YELHND ==2 ;YELLOW HAND
BLUARM ==4 ;BLUE ARM, NOT INCLUDING HAND
BLUHND ==10 ;BLUE HAND
GRNARM ==100 ;GREEN ARM (PUMA NEAR DOOR)
GRNHND ==200 ;GREEN HAND
REDARM ==400 ;RED ARM (PUMA NEAR WALL)
REDHND ==1000 ;RED HAND
;THE FOLLOWING BITS ARE USED BY THE FORCE SENSING ROUTINES TO INDICATE
;IF THE FORCE TRANSFORMATION IS IN TABLE OR HAND COORDINATES.
FTABLE ==400 ;TABLE COORDINATES
FHAND ==0 ;HAND COORDINATE SYSTEM
.MACRO SQRFIX X ;IF X IS A SMALL NEGATIVE NUMBER, MAKE IT ZERO.
CHECKF X ;IS IT POSITIVE OR ZERO?
BGE .+16 ;IF SO, EXIT
COMPF TINYNO,X ;IS TINY# > X?
BGT .+6
CLRF X ;IT'S DUE TO ROUNDING, PROBABLY. CLEAR IT.
.ENDM
;DEFINITIONS FOR USING THE MATRICES AND VECTORS:
;Transformation definitions for the Stanford Arm routines
T11==0
T21==4
T31==10
T12==14
T22==20
T32==24
T13==30
T23==34
T33==40
T14==44
T24==50
T34==54
;Transformation definitions for the PUMA routines
NX == 0 ;First row of the position matrix (see PUMSOL for details)
NY == 4
NZ == 10
OX == 14 ;Second row
OY == 20
OZ == 24
AX == 30 ;Third row
AY == 34
AZ == 40
PX == 44 ;Fourth row
PY == 50
PZ == 54
TH1 == 0 ;DEFINITIONS FOR A 6-VECTOR OF JOINT ANGLES POINTERS
TH2 == 2
TH3 == 4
TH4 == 6
TH5 == 8.
TH6 == 10.
XCOORD == 0 ;COMPONENTS OF 3-VECTORS
YCOORD == 4
ZCOORD == 10
FARBIT==400 ;This bit is set in R0 if a close solution was not found.
; ---> SOLVE <--- THE STANFORD ARM SOLUTION
;GIVEN A TRANSFORM "T", THE REQUIRED JOINT ANGLES ARE DETERMINED IN DEGREES.
;IF ANY JOINT ANGLE IS OUTSIDE OF THE PERMITTED RANGE OF MOVEMENT, THE STOP
;LIMIT ANGLE CLOSEST TO THE PREVIOUS JOINT ANGLES COMPUTED IS RETURNED.
;IN THE DETERMINATION OF JOINT ANGLE 4, IF THE REQUIRED CHANGE IN ANGLE IS
;GREATER THAN 90 DEGRESS AND LESS THAN 180, THE HAND IS FLIPPED OVER AND THE
;JOINT ANGLE CHANGE BECOMES THETA = THETA-90. ON COMPLETION OF EXECUTION,
;REGISTER R0 CONTAINS BITS INDICATING THOSE JOINTS FOR WHICH NO SOLUTION
;COULD BE FOUND WITHIN THE RANGE OF JOINT MOTION. A SAMPLE CALLING SEQUENCE
;TO "SOLVE" FOLLOWS:
;
; MOV #T,R0 ;LOAD ADDRESS OF TRANSFORM "T"
; MOV #THETA,R1 ;PTR TO A TABLE CONTAINING POINTERS TO THE
; ; JOINT ANGLES FOR ALL EXISTING ARM JOINTS,
; ; I.E., THE TABLE MUST HAVE 28 ELEMENTS,
; ; 7 FOR EACH ARM.
; MOV #MECHSM,R2 ;CONSTANT INDICATING WHICH ARM TO USE
; JSR PC,SOLVE ;CALLED USING PC
; TST R0 ;CHECK FOR NUMBER OF NON-EXACT SOLUTIONS
;
;IF THE BLUE OR YELLOW HAND IS SPECIFIED AS THE MECHANISM, THIS ROUTINE
;PUTS THE VALUE POINTED TO BY "T" INTO ITS APPROPRIATE SPOT IN THE "THETA"
;ARRAY. ALL NUMBERS SHOULD BE IN SINGLE PRECISION FLOATING POINT
;REPRESENATATION.
;EXECUTION TIME: 2200 MICRO SECONDS
;REGISTERS USED:
;
; R0, R1 PASS ARGUMENTS AND ARE ALTERED BY "SOLVE".
; R2 PASSES ARGUMENTS AND IS UNALTERED.
; AC0, AC1, AC2, AND AC3 ARE GARBAGED
;THE OUT OF RANGE BITS THAT ARE RETURNED IN R0 ARE DEFINED AS FOLLOWS:
JT1== 1 ;JOINT 1
JT2== 2 ; " 2 (NOT USED FOR STANFORD ARMS)
JT3== 4 ; " 3
JT4== 10 ; " 4
JT5== 20 ; " 5
JT6== 40 ; " 6
; ["SOLVE" - CHECK IF ARM OR HAND]
CODE
SOLVE: CLR EXACTS ;ASSUME EXACT SOLUTION FOUND
MOV R5,-(SP) ;SAVE REGISTER
BIT #BLUHND+YELHND+GRNHND+REDHND,R2 ;CHECK IF A HAND IS SPECIFIED
BEQ 1$ ;BRANCH IF NOT
; CODE TO HANDLE HANDS
; NOT SURE WHAT TO DO HERE FOR THE PUMA
LDF (R0),AC0 ;GET THE REQUESTED HAND OPENING
ADD #12.,R1 ;POINT TO THE YELLOW HAND CELL
BIT #BLUHND,R2 ;CHECK WHICH HAND
BEQ .+6
ADD #14.,R1 ;POINT TO BLUE HAND
STF AC0,@(R1) ;SAVE THE HAND OPENING
JMP SOLDNE ;AND EXIT
; CODE TO HANDLE ARMS
1$: BIT #GRNARM+REDARM,R2 ;IS IT A PUMA??
BEQ 10$ ;IF NOT, GO INTO STANFORD ARM SOL'N
MOV #GCON,R5 ;ASSUME GREEN ARM & SET R5 TO CONSTANT TABLE
ADD #32.,R1 ;POINT TO GREEN ARM ANGLES.
BIT #REDARM,R2 ;WAS IT ACTUALLY THE RED ARM?
BEQ 20$ ;IF NOT, BR
MOV #RCON,R5 ;SET R5 TO RED ARM CONSTANTS
ADD #14.,R1 ; AND BUMP R1 TO RED ARM ANGLES.
20$: JSR PC,PUMSOL ;GET PUMA SOLUTION
POP R5 ;POP R5 FROM STACK
RTS PC ;RETURN
10$: MOV #YCON,R5 ;MUST BE STANFORD ARM. GET PTR TO YELLOW CONSTANTS
BIT #YELARM,R2 ;SWITCH CONSTANTS IF BLUE ARM
BNE 2$
MOV #BCON,R5
ADD #14.,R1 ;POINT TO BLUE ARM JT. ANGLES
;COMPUTE POSITION OF THE END OF THE BOOM: TX,TY,TZ. ALSO COMPUTE
;SQRT(TX**2+TY**2-S2**2) FOR LATER
2$: LDF S6(R5),AC1 ;GET OFFSET OF JT. 6: S6
NEGF AC1
LDF T13(R0),AC0 ;TX ← T14 - T13*S6 - X BASE POS.
MULF AC1,AC0
SUBF BASEX(R5),AC0
ADDF T14(R0),AC0
STF AC0,TX ;SAVE TX
MULF AC0,AC0 ;AC0 ← TX**2
LDF T23(R0),AC2 ;TY ← T24 - T23*S6 - Y BASE COORD.
MULF AC1,AC2
SUBF BASEY(R5),AC2
ADDF T24(R0),AC2
STF AC2,TY ;SAVE TY
MULF AC2,AC2 ;AC0 ← TX**2 + TY**2
ADDF AC2,AC0
MULF T33(R0),AC1 ;TZ ← T34 - T33*S6
ADDF T34(R0),AC1
STF AC1,TZ ;SAVE TZ
SUBF S22(R5),AC0 ;AC0 ← TX**2 + TY**2 - S2**2
CFCC ;CHECK IF RESULT > 0
BGT 3$
CLRF AC0 ;IF <0 SET TO 0 AND INDICATE ERROR
BIS #JT1,EXACTS ;THIS WILL CAUSE JT 1 TO BE WRONG
3$: JSR PC,SQRTF
NEGF AC0
STF AC0,SQRTXY ;SAVE -SQRT(TX**2+TY**2-S2**29
; ["SOLVE" - JOINT 1]
;COMPUTE JOINT 1 ANGLE
SUBF TX,AC0 ;TAN TH1/2= (-TX-(TX↑2+TY↑2-S2↑2)↑.5)/(S2+TY)
LDF TY,AC1 ;INDETERMINANT? IS S2+TY = 0 ?
ADDF S2(R5),AC1
STF AC1,AC2 ;COMPARE TO .001
ABSF AC2
CMPF C001,AC2
CFCC
BLT 5$ ;BRANCH IF DENOMINATOR NOT ZERO
TST TX ;ELSE CHECK IF INDETERMINATE OR SPECIAL CASE
BLT 4$ ;BRANCH IF INDETERMINATE FORM OF EQU. NECESSARY
LDF C180,AC0 ;ELSE THETA 1 = 180 DEGREES
BR JT1CHK ;NOW GO CHECK LIMITS
4$: LDF TY,AC0 ;TAN TH1/2 = TY/TX
LDF TX,AC1
5$: TSTF AC1 ;-90 < TH1/2 < 90
CFCC
BGE JT1CPU
NEGF AC0
NEGF AC1
JT1CPU: JSR PC,ATAN2 ;COMPUTE THETA 1/2
MULF #40400,AC0 ;THETA 1
JT1CHK: CMP #YELARM,R2 ;CHECK IF YELLOW OR BLUE ARM
BNE 1$ ;BRANCH IF BLUE ARM
CMPF STOP1+4(R5),AC0 ;IF YELLOW, CHECK IF LESS THAN +90 DEG
CFCC
BGE .+6 ;SKIP IF LESS THAN MAX STOP LIMIT
SUBF C360,AC0 ;ELSE SUBTRACT 360 DEGREES
CMPF STOP1(R5),AC0 ;COMPARE TO MIN STOP LIMIT
CFCC
BLE J1OK ;BRANCH IF WITHIN STOP LIMITS
BR 2$
1$: CMPF STOP1(R5),AC0 ;IF BLUE, CHECK IF GREATER THAN -90 DEG
CFCC
BLE .+6 ;SKIP IF GREATER THAN
ADDF C360,AC0 ;ELSE ADD 360 DEGREES
CMPF STOP1+4(R5),AC0 ;COMPARE ANGLE TO MAX STOP LIMIT
CFCC
BGE J1OK ;BRANCH IF WITHIN STOP LIMITS
2$: BIS #JT1,EXACTS ;INDICATE NO EXACT SOLUTION
LDF STOP1(R5),AC0 ;USE CLOSEST STOP LIMIT
LDF MIDDY1(R5),AC1 ;MID-RANGE ANGLE
CMPF @(R1),AC1 ;COMPARE TO PREVIOUS
CFCC
BLE J1OK
LDF STOP1+4(R5),AC0 ;USE MAXIMUM IF CLOSER
J1OK: STF AC0,@(R1)+ ;SEND OFF NEW JOINT 1 ANGLE
JSR PC,SNCOS ;COMPUTE SIN/COS THETA 1 FOR LATER
STF AC0,ST1
STF AC1,CT1
; ["SOLVE" - JOINTS 2 & 3]
;COMPUTE JOINT 2 ANGLE
LDF SQRTXY,AC0 ;TAN TH2 = -(TX↑2+TY↑2-S2↑2)↑.5/(TZ-S1)
LDF TZ,AC1
SUBF S1(R5),AC1
JSR PC,ATAN2
STF AC0,@(R1)+ ;SEND OF NEW JOINT 2 ANGLE. NO STOP LIMIT
; CHECKING SINCE ALL SOLUTIONS WITHIN 0 TO Pi
JSR PC,SNCOS ;COMPUTE SIN/COS OF THETA 2 FOR LATER
SUBF C000,AC0 ;MAKE SURE SINE THETA 2 NOT ZERO
STF AC0,ST2
STF AC1,CT2
;COMPUTE JOINT 3 LENGTH
LDF TX,AC2 ;S3 ← (TX*CT1+TY*ST1)/ST2
MULF CT1,AC2
LDF TY,AC3
MULF ST1,AC3
ADDF AC3,AC2
DIVF AC0,AC2 ;NOW HAVE S3
CMPF STOP3+4(R5),AC2 ;COMPARE TO MAX. JOINT EXTENSION
CFCC
BGE 1$ ;BRANCH IF LESS THAN MAX
LDF STOP3+4(R5),AC2 ;ELSE SUBSTITUE MAX ALLOWABLE EXT.
BR 2$
1$: CMPF STOP3(R5),AC2 ;COMPARE TO MIN. JOINT EXTENSION
CFCC
BLE S3OK ;BRANCH IF IN RANGE
LDF STOP3(R5),AC2 ;ELSE SUBSTITUTE MIN LENGTH
2$: BIS #JT3,EXACTS ;INDICATE EXACT SOLUTION NOT FOUND
S3OK: STF AC2,@(R1)+ ;SEND BACK JOINT 3
; ["SOLVE" - JOINT 5]
;COMPUTE COS/SIN OF THETA 5 AND CHECK FOR DEGENERACY
LDF T13(R0),AC0 ;SIN TH5 = SQRT( (-T33*SN2+(T13*CT1+T23*ST1)*CT2)↑2
MULF CT1,AC0 ; + (T13*ST1-T23*CT1)↑2 )
LDF T23(R0),AC1
MULF ST1,AC1
ADDF AC1,AC0
STF AC0,T13T23 ;SAVE T13*CT1+T23*ST1
MULF CT2,AC0
LDF T33(R0),AC1
MULF ST2,AC1
SUBF AC1,AC0
STF AC0,ST4 ;THIS IS ALMOST SIN(THETA 4)
MULF AC0,AC0
LDF T13(R0),AC1 ;NOW GET T13*ST1-T23*CT1
MULF ST1,AC1
LDF T23(R0),AC2
MULF CT1,AC2
SUBF AC2,AC1
STF AC1,CT4 ;THIS IS ALMOST COS(THETA 4)
MULF AC1,AC1
ADDF AC1,AC0
JSR PC,SQRTF ;NOW HAVE SIN(THETA 5)
LDF T13T23,AC1 ;COS TH5 = T33*CT2+(T13*CT1+T23*ST1)*ST2
MULF ST2,AC1
LDF T33(R0),AC2
MULF CT2,AC2
ADDF AC2,AC1
JSR PC,ATAN2
ABSF AC0 ;WANT +180 NOT -180
TST @2(R1) ;CHECK SIGN OF PREVIOUS THETA 5
BGE .+4
NEGF AC0 ;SET SIGN OF CURRENT ANGLE THE SAME
CMPF STOP5+4(R5),AC0 ;COMPARE TO MAXIMUM STOP LIMIT
CFCC
BGE 1$ ;BRANCH IF ANGLE LESS THAN STOP LIMIT
LDF STOP5+4(R5),AC0 ;ELSE REPLACE ANGLE BY STOP LIMIT
BR 2$
1$: CMPF STOP5(R5),AC0 ;COMPARE ANGLE TO MIN STOP LIMIT
CFCC
BLE JT5OK ;BRANCH IF ANGLE IN RANGE
LDF STOP5(R5),AC0 ;ELSE REPLACE ANGLE BY MIN STOP LIMIT
2$: BIS #JT5,EXACTS ;INDICATE NO EXACT SOLUTION FOUND
JT5OK: STF AC0,@2(R1) ;SEND BACK ANGLE
STF AC0,AC1 ;CHECK FOR DEGENERATE CASE, TH5 = 0
ABSF AC1
CMPF C01,AC1
CFCC
BLT NOTDGN ;BRANCH IF NOT DEGENERATE SOLUTION
; ["SOLVE" - DEGENERATE SOLUTION AND JOINT 4]
;DEGENERATE SOLUTION: TH5 = 0, TH4 REMAINS THE SAME, SPECIAL
;EQUATION FOR TH6
LDF T31(R0),AC0 ;SIN(TH6+TH4)=-T31/ST2
LDF T32(R0),AC1 ;COS(TH6+TH4)=-T32/ST2
JSR PC,ATAN2 ;COMPUTE TH6+TH4
SUBF @(R1)+,AC0 ;TH6 = ATAN -TH4
TST (R1)+
CMPF STOP6+4(R5),AC0 ;MIGHT BE OFF BY 360 DEG
CFCC ;GREATER THAN MAXIMUM STOP LIMIT?
BGE 1$
SUBF C360,AC0 ;YES, SUBTRACT 360 DEGREES
JMP JT6CHK ;GO CHECK IF JT 6 IN RANGE
1$: CMPF STOP6(R5),AC0 ;LESS THAN MINIMUM STOP LIMIT?
CFCC
BLE 2$
ADDF C360,AC0 ;YES, ADD 360 DEGREES
2$: JMP JT6CHK
;NON-DEGENERATE SOLUTION: COMPUTE THETA 4
NOTDGN: LDF ST4,AC0 ;SIN(THETA 4)=-T33*SN2+(T13*CT1+T23*ST1)*CT2/ST5
LDF CT4,AC1 ;COS(THETA 4)=(T13*ST1-T23*CT1)/ST5
TST @2(R1) ;DONT DIVID, JUST CORRECT FOR SIGN(ST5)
BPL 1$
NEGF AC0
NEGF AC1
1$: JSR PC,ATAN2 ;COMPUTE THETA 4
STF AC0,AC1 ;DIFFERENCE BETWEEN OLD AND NEW ANGLE
SUBF @(R1),AC1
CMPF C180,AC1 ;DIFFERENCE > 180 DEG ?
CFCC
BGE 2$ ;BRANCH IF LESS
SUBF C360,AC0 ;ELSE SUBT. 360 DEG - GO THE SHORTEST DIRECTION
SUBF C360,AC1
BR 3$
2$: CMPF CM180,AC1 ;DIFFERENCE > -180 DEG ?
CFCC
BLE 3$ ;BRANCH IF GREATER
ADDF C360,AC0 ;ELSE ADD 360 DEG - GO THE SHORTEST DIRECTION
ADDF C360,AC1
3$: CMPF C90,AC1 ;DIFF. < 90 DEG ?
CFCC
BGE 4$ ;BRANCH IF IT IS
SUBF C180,AC0 ;ELSE GO THE OTHER DIRECTION AND FLIP HAND
BR FLIPJ4
4$: CMPF CM90,AC1 ;DIFF. > -90 DEG ?
CFCC
BLE JT4CHK ;BRANCH IF IT IS
ADDF C180,AC0 ;ELSE GO THE OTHER DIRECTION
FLIPJ4: NEGF @2(R1) ;FLIP HAND OVER
JT4CHK: CMPF STOP4(R5),AC0 ;COMPARE ANGLE TO MIN STOP LIMIT
CFCC
BLE 1$ ;BRANCH IF GREATER THAN MIN
ADDF C180,AC0 ;ELSE ADD 180 DEG AND FLIP HAND
BR 2$
1$: CMPF STOP4+4(R5),AC0 ;COMPARE TO MAX STOP LIMIT
CFCC
BGE JT4OK ;BRANCH IF JT 4 IN RANGE
SUBF C180,AC0 ;ELSE SUBT 180 DEG AND FLIP HAND
2$: NEGF @2(R1)
JT4OK: STF AC0,@(R1)+ ;SEND BACK THE NEW JOINT 4 ANGLE
; ["SOLVE" - JOINT 6]
;COMPUTE THETA 6
LDF ST1,AC2 ;SIN(THETA 6)=((T12*CT1+T22*ST1)*ST2
LDF CT1,AC3 ; +T32*CT2)/ST5
LDF T12(R0),AC0
MULF AC3,AC0
LDF T22(R0),AC1
MULF AC2,AC1
ADDF AC1,AC0
MULF ST2,AC0
LDF T32(R0),AC1
MULF CT2,AC1
ADDF AC1,AC0
LDF T21(R0),AC1 ;COS(THETA 6)=-((T21*ST1+T11*CT1)*ST2
MULF AC2,AC1 ; +T31*CT2)/ST5
LDF (R0),AC2
MULF AC3,AC2
ADDF AC2,AC1
MULF ST2,AC1
LDF T31(R0),AC2
MULF CT2,AC2
TST @(R1) ;DON'T DIVID BY ST5, JUST CORRECT SIGN
ADDF AC2,AC1
BGE 1$
NEGF AC0 ;IF SIN(TH5)<0 USE -SIN(TH6)
BR .+4
1$: NEGF AC1 ;ELSE USE -COS(TH6)
TST (R1)+ ;POINT TO OLD THETA 6
JSR PC,ATAN2 ;COMPUTE THETA 6
JT6CHK: CMPF STOP6(R5),AC0 ;CHECK IF ANGLE GREATER THAN MIN.
CFCC
BLE 1$ ;BRANCH IF GREATER
ADDF C180,AC0 ;ELSE ADD 180 DEG AND FLIP HAND
BR 2$
1$: CMPF STOP6+4(R5),AC0 ;CHECK IF ANGLE LESS THAN MAXIMUM
CFCC
BGE JT6OK ;BRANCH IF JT6 IN RANGE
SUBF C180,AC0 ;ELSE SUBT 180 DEG AND FLIP HAND
2$: STF AC0,@(R1) ;SAVE NEW THETA 6
NEGF @-(R1) ;FLIP HAND BY COMPLEMENTING TH5
LDF @-(R1),AC0 ;ALTER THETA 4 BY 180 DEGREES
ADDF C180,AC0 ;TRY ADDING 180 DEGREES
CMPF STOP4+4(R5),AC0 ;COMPARE TO MAXIMUM
CFCC
BGE 3$ ;BRANCH IF STILL IN RANGE
SUBF C360,AC0 ;ELSE TRY SUBT 180 DEGREES
CMPF STOP4(R5),AC0
CFCC
BLE 3$ ;BRANCH IF JT 4 NOW IN RANGE
LDF STOP4(R5),AC0 ;ELSE JUST USE STOP LIMIT
BIS #JT4,EXACTS ;INDICATE NO EXACT SOLUTION
3$: STF AC0,@(R1) ;SAVE NEW THETA 4
BR .+6
JT6OK: STF AC0,@(R1) ;SAVE NEW THETA 6
;EXIT CLEANLY
SOLDNE: MOV (SP)+,R5 ;RESTORE REGISTERS
MOV EXACTS,R0 ;LEAVE ERROR BITS FOR CALLER
RTS PC
;END OF "SOLVE"
; ["SOLVE" LOCAL STORAGE AREA]
DATA
TX: .BLKW 2 ;LOCATION OF THE END OF THE BOOM
TY: .BLKW 2
TZ: .BLKW 2
SQRTXY: .BLKW 2 ;-SQRT(TX**2+TY**2-S2**2)
T13T23: .BLKW 2 ;T13*CT1+T23*ST1
ST1: .BLKW 2 ;SIN/COS THETA 1
CT1: .BLKW 2
ST2: .BLKW 2 ;SIN/COS THETA 2
CT2: .BLKW 2
ST4: .BLKW 2 ;SIN/COS THETA 4 (ALMOST)
CT4: .BLKW 2
EXACTS: 0 ;INDICATES JTS WITH NON-EXACT SOLUTIONS
;CONSTANTS
C01: .WORD 37314,146315 ; .1000000
C001: .WORD 35603, 11157 ; .1000000@-2
C360: .WORD 42264, 0 ; 360.0000
C90: .WORD 41664, 0 ; 90.00000
CM90: .WORD 141664, 0 ;-90.00000
C180: .WORD 42064, 0 ; 180.0000
CM180: .WORD 142064, 0 ;-180.0000
C000: .WORD 31453,146167 ; .1000000@-7
CODE
; ---> PUMSOL <--- THE PUMA ARM SOLUTION
; PUMSOL does the forward solution for the PUMA: it accepts a required position
; represented by a 4x4 matrix, and returns the 6 joint angles necessary to
; achieve this position. For each position, there correspond four possible
; solutions, since the arm can look like a right or left hand, and the elbow
; can be above or below the rest of the arm. In many cases, one or more or
; these solutions may not be valid because of joint stop limits or because
; the solution would cause the arm to reach into itself. This routine uses
; the current position, which is assumed to be in a vector of 6 joint angles
; pointed to by r2, to generate the solution closest to the current position.
; If none of the four solutions are valid, a bit in r3 is set to indicate
; which joint produced an invalid solution.
; In the case of a 5-degree of freedom arm, such as the PUMA with 5 joints,
; some frames may not be accessible by the manipulator. For example, we
; must constrain the angle of joint 4 to be zero, so that any frame accessible
; will be such that the A vector (which lies along the tool axis) is in a
; vertical plane passing through the desired position (P vector) and tangent
; to the circle of radius D3 with center at (0,0,0).
; To achieve this, we must perform a rotation of the goal frame to make it
; correspond to one of these accessible positions. The method used to rotate
; the goal frame is as follows:
; Call the circle of radius D3 about the origin C. This circle defines an
; infinite set of (vertical) planes, each tangent to the circle C, in which
; the approach vector A must lie in order for the goal frame to be accessible
; by the arm. The goal position (specified by the vector P) defines which one
; of these planes A must lie in: it is the plane passing through P and tangent
; to the circle C. Call the point of tangency (r,s,0). We have
; r1 = [Px*D3 - Py*sqrt(D↑2-D3↑2)] / D↑2 s1 = [Py*D3 + Px*sqrt(D↑2-D3↑2] / D↑2
; r2 = [Px*D3 + Py*sqrt(D↑2-D3↑2)] / D↑2 s1 = [Py*D3 - Px*sqrt(D↑2-D3↑2] / D↑2
; with
; D↑2 = Px↑2 + Py↑2
; These two solutions for (r,s) correspond to the two points of tangency to C.
; We choose for (r,s) the values which make the rotation angle needed the minimum.
; Denote by T the normal vector to the plane. Now there are two choices for T
; also. We choose the one which points in the same general direction as A.
; Let T=(r,s,0) and T'=(-r,-s,0). These are our two choices. If we have
; arccos(A⊗T) < π/2 then assign T ← T'.
; Now let S = A x J, where J is A's projection on the plane we have been talking
; about. We have J = A - (T⊗A)T, and this must be made into a unit vector.
; S must be a unit vector also for the next step. The angle needed to rotate
; the goal frame through is theta = arccos(J⊗A).
; We now get A' and O' from A and O, the desired goal frame vectors, by rotating
; both of them about S by an angle theta, with theta as above. We use
; Rodrigues' formula for rotation of vectors, e.g. to rotate V about S by angle α:
; V' = V cosα + (SxA) sinα + (S⊗A) (1-cosα) S
; This vector is unitized and stored into A and O to be used in the calculations
; of the joint angles.
; Given the vector (r,s), this is the vector along which the axis of joint 2
; (the shoulder joint) must lie -- it points along the angle of joint 1.
; Thus, to calculate theta1 we need only find the arctangent of (s,r) and
; subtract 90 degrees from this result [to make it 0 when (r,s)=(1,0)].
; Another simplification is made by forcing theta4 to be zero.
; Another parameter to this routine is the global variable EXACT, which is set
; to 0 to mean Solve is to find the solution which yields an arm configuration
; as close as possible to the desired orientation. On the other hand, if EXACT
; is nonzero, then Solve will find the solution which preserves the current arm
; configuration, i.e. Lefty or Righty. This is useful when moving the arm in
; keyboard control mode, in a straight line (you don't want the arm to suddenly
; change configuration).
; The way we do this is not analytical. We proceed as usual and find the arm
; solution closest to the desired orientation. We then see how much these
; angles differ from the current ones. If EXACT is nonzero, the difference
; for angles 1 and 2 cannot be too great; it must be less than about 5 degrees.
; If it is too great, we generate another arm solution, using the other rotation.
; ARGUMENTS:
; R0 - Points to the matrix C, which contains 16 floating-point
; (single precision) numbers which represent the desired
; position of the arm. The matrix looks like
; | Nx Ox Ax Px |
; | Ny Oy Ay Py |
; | Nz Oz Az Pz |
; | 0 0 0 1 |
; (N, O and A are unit vectors: i.e. the X axis of the frame
; points along N, the Y axis points along O, and the Z axis points
; along A; P is the position vector)
; The matrix must be stored in column-major order -- i.e. R0 points
; to Nx, which is followed by Ny, etc.
; R1 - On entry, points to a 6-vector J which contains pointers to
; the current joint angles, which we use to insure the solution
; produced is "close".
; R5 - Points to a table of arm constants which are used to relocate
; the base of the coordinate system. The origin of the PUMA's
; world is at the base of its shoulder, so we need to know the
; offset of this base and subtract it off from the place AL
; wants us to move to. R5 must point to a 3-vector of floating-pt
; numbers (X0,Y0,Z0) which is the location of the PUMA's base.
; RETURNED VALUES:
; R0 - On return, R0 is set to indicate which joints could not be
; solved for, or cleared if a valid solution was found.
; Also, if the "close" solution could not be found, the bit
; FARBIT is set on in R0 to indicate this.
; R1 - Unchanged, but the 6 joint angles referenced by R1 have been
; changed to those angles necessary to move the arm to the
; position defined by matrix C. These will be single-precision
; floating numbers, in degrees.
; SAMPLE CALLING SEQUENCE:
; MOV #MATRIX,R0 ;Set up address of cartesian matrix
; MOV #JVECT,R1 ;Set up address of result (joint vector)
; MOV #CONST,R5 ;Pointer to arm constants (ie offset of origin)
; JSR PC,PUMSOL ;Get FORWARD SOLUTION.
; TST R0 ;Check for invalid solution
; REGISTERS USED:
; R0,R1,R5: For passing arguments. R0 & R5 are changed.
; AC0,AC1,AC2,AC3: Garbaged.
; ["PUMSOL" - THE MAIN PART]
PUMSOL: PUSH R2
PUSH R3
PUSH R4 ;save registers we may use
MOV R5,PWHICH ;Save pointer to arm constants
GOSUB SSETUP ;set up arguments - NX,NY,NZ,OX,etc.
CLR FAR ;Assume we found close sol'n
LDF @TH1(R1),AC0 ;SAVE CURRENT JOINT 1 ANGLE
STF AC0,CUR1
LDF @TH2(R1),AC0 ;CURRENT JOINT 2 ANGLE
STF AC0,CUR2
; Rotate the goal frame as described above. Figure out two pairs (r,s) and
; use the one which causes the smaller rotation.
LDF PXHOLD,AC0 ;Calculate Px↑2 + Py↑2
MULF AC0,AC0
LDF PYHOLD,AC1
MULF AC1,AC1
ADDF AC1,AC0 ;AC0 ← Px↑2 + Py↑2 = D↑2
STF AC0,AC2 ;Store D↑2 in AC2
LDF D3,AC1 ;Calculate D3↑2, store in AC1
MULF AC1,AC1
SUBF AC1,AC0 ;AC0 ← D↑2 - D3↑2
SQRFIX AC0 ;If it's negative but not too much, make it zero
CHECKF AC0 ;Is it negative?? If so, no sol'n!
BGE 10$ ; but if D↑2 ≥ D3↑2, it's OK
MOV #JT1,R3 ;Set bit for no sol'n, joint 1
JMP 100$ ; & exit
10$: GOSUB SQRTF ;Find sqrt (...), put in AC0
STF AC0,SQ ;Store sqrt (D↑2-D3↑2)
LDF PXHOLD,AC0 ;Now calculate r1,s1 and r2,s2
MULF D3,AC0 ;r1 ← (Px*D3 - Py*sq)/D↑2
LDF PYHOLD,AC1
MULF SQ,AC1
SUBF AC1,AC0
DIVF AC2,AC0 ; remember, D↑2 is in AC2
STF AC0,T1 ;Store 1st part (x component) of T1 (this is r1)
LDF PYHOLD,AC0 ;Calculate s1 = (Py*D3 + Px*sq)/D↑2
MULF D3,AC0
LDF PXHOLD,AC1
MULF SQ,AC1
ADDF AC1,AC0
DIVF AC2,AC0
STF AC0,T1+4 ; store in 2nd part (y component) of T1 (this is s1)
LDF PXHOLD,AC0 ;Calculate r2 = (Px*D3 + Py*sq)/D↑2
MULF D3,AC0
LDF PYHOLD,AC1
MULF SQ,AC1
ADDF AC1,AC0
DIVF AC2,AC0
STF AC0,T2 ; store 1st part (x component) of T2 (this is r1)
LDF PYHOLD,AC0 ;Calculate s2 = (Py*D3 - Px*sq)/D↑2
MULF D3,AC0
LDF PXHOLD,AC1
MULF SQ,AC1
SUBF AC1,AC0
DIVF AC2,AC0
STF AC0,T2+4 ; store 2nd part (y component) of T2 (this is s2)
MOV #T1,R4 ;Now find corresponding vector S to rotate the
MOV #SA,R5 ; goal frame about. Store the S corresponding to
GOSUB FINDS ; T1 in SA.
STF AC2,RANG1 ;Rotation angle needed for T1 - store in RANG1.
MOV #T2,R4 ;Same for vector SB corresponding to T2.
MOV #SB,R5
GOSUB FINDS
STF AC2,RANG2
COMPF RANG1,AC2 ;Is RotAng1 ≤ RotAng2? We want it this way.
BLE 30$ ;If SA means smaller rotation, use it & br
EXCHGF T1,T2 ;Switch things so SA is the smaller rotation.
EXCHGF T1+4,T2+4
EXCHGF RANG1,RANG2
EXCHGF SA,SB
EXCHGF SA+4,SB+4
EXCHGF SA+10,SB+10
30$: MOV #SA,R4 ;Now do the actual rotation. The vectors to be
LDF RANG1,AC2 ;rotated start at AXHOLD & OXHOLD. Rotate about SA
GOSUB ROT3 ;by RANG1 degrees.
GOSUB OFSETS ;Account for length of tool.
MOV #T1,R4 ;Use (R1,S1) to generate theta1.
GOSUB GETSOL ;See if there is a solution.
TSTB R3 ;Was there a solution? If so, br
BEQ 100$
TST EXACT ;Looking for exact sol'n? If so, don't set far bit
BNE 35$
MOV #FARBIT,FAR ;Means we didn't find close sol'n
35$: GOSUB SSETUP ;Set up arguments again (from R0)
MOV #SB,R4 ;Rotate about SB now
LDF RANG2,AC2
GOSUB ROT3
GOSUB OFSETS ;Again account for the length of the tool
MOV #T2,R4 ;Now use (R2,S2) to generate theta1.
GOSUB GETSOL ;Again try to get a solution.
100$: BIS FAR,R3 ;Set bit for far sol'n
MOV R3,R0 ;Set up result - bits for no joint sol'n
POP R4
POP R3
POP R2
RTS PC
; ["PUMSOL" - GETSOL]
; Called with R4 pointing to the vector (R,S) along which the axis
; of joint 2 must lie -- used to generate theta1.
GETSOL: MOV #1,CLOSE2 ;First try to get close sol'n for joint 2.
SOLV1: CLR R3 ;assume exact solution found
JSR PC,GET1 ;get solution for joint angle 1
STF AC0,@TH1(R1) ;and store in result joint angle vector
MOV #TH1,R5 ;set R5 to joint 1 for check.
JSR PC,CHKJNT ;see if within joint stops. If not, set error flag
TST R3 ;was joint 1 solution invalid?
BNE SEXIT ;If not ok, exit; no point retrying
TST EXACT ;Looking for Exact sol'n?
BEQ 5$ ;no - continue
LDF @TH1(R1),AC0 ;Find how much Calculate theta1 differs from current
LDF CUR1,AC1
JSR PC,DIST ;Put |calculated - current| in AC2
COMPF JT1EXA,AC2 ;Compare to maximum difference allowed.
BGE 5$ ;if Max ≥ diff, OK -- This is exact, and continue
MOV #7,R3 ;Indicate no sol'n for joint 7 so I can tell
BR SEXIT ;And exit, with no retry.
5$: JSR PC,GET3 ;generate 2 possible angles for theta3.
JSR PC,GET2 ;solve for theta2, decide which theta3 to use too.
STF AC0,@TH2(R1) ;save result: theta2.
MOV #TH2,R5 ;check joint 2 now
JSR PC,CHKJNT ;see if within joint stops.
TST R3
BNE RETRY ;if jt2 sol'n invalid, retry the solution
LDF @TH3(R1),AC0 ;now we'll check our result for theta3
MOV #TH3,R5 ;about to check joint 3
JSR PC,CHKJNT ;see if within joint stops. if not, set error flag
TST R3 ;solution for joint 3 valid?
BNE RETRY ;if not, see if there are more sol'ns to generate.
TST EXACT ;Looking for Exact sol'n?
BEQ 10$ ;no - continue
LDF @TH2(R1),AC0 ;Find how much Calculate theta2 differs from current
LDF CUR2,AC1
JSR PC,DIST ;Put |calculated - current| in AC2
COMPF JT2EXA,AC2 ;Compare to maximum difference allowed.
BGE 10$ ;if Max ≥ diff, OK -- This is exact, and continue
MOV #7,R3 ;Indicate no sol'n for joint 7 so I can tell
BR SEXIT ;And exit, with no retry.
10$: JSR PC,GET4 ;get sol'ns for joints 4,5 and 6
STF AC0,@TH4(R1)
JSR PC,GET5
STF AC0,@TH5(R1)
JSR PC,GET6
STF AC0,@TH6(R1)
;If theta4=180, rotate the hand 180 degrees. Also check for degenerate solution.
JSR PC,FIX4
LDF @TH4(R1),AC0 ;put joint4 angle in AC0 for check
MOV #TH4,R5 ;about to check joint 4
JSR PC,CHKJNT ;is angle out of range? If so, set R3 to indicate.
TST R3 ;if invalid sol'n, then retry it
BNE RETRY
LDF @TH5(R1),AC0
MOV #TH5,R5
JSR PC,CHKJNT
TST R3 ;if invalid sol'n, then retry it
BNE RETRY
LDF @TH6(R1),AC0
MOV #TH6,R5
JSR PC,CHKJNT
TST R3 ;if invalid sol'n, then retry it
BEQ SEXIT ;but if sol'n is good, then exit.
RETRY: TST CLOSE2 ;If CLOSE2 is zero, we give up
BEQ SEXIT
CLR CLOSE2 ;try far solution for joint 2
MOV #FARBIT,FAR ;Means this is not the close sol'n
BR SOLV1
SEXIT: RTS PC ;return to caller
; ["PUMSOL" - SSETUP]
; Routine to get the vector components out of the array pointed to by R0
; and put them into `hold' words so we can modify the goal frame if needed.
; Note we don't use the `N' vector in the calculation, so there's no
; need to retrieve it from the array.
; Due to the fact that the x-y axis of the Green PUMA's world is rotated
; 180 degrees from that used by AL, we need to change the N and O vectors
; accordingly. The appropriate transformation is to negate the X and Y
; components of these vectors.
; We also need to account for the fact that the origin of the PUMA's world is
; at the center of its shoulder, while the origin of AL's world is at the corner
; of the table. So we need to offset the position vectors by the appropriate
; amount. The transformation is: (x,y,z) → (x0-x,y0-y,z-z0) for the Green arm
; and (x,y,z) → (x-x0,y-y0,z-z0) for the Red arm, where (x0,y0,z0) is the
; location of the PUMA origin in AL's world and (x,y,z) is the goal point.
; This routine is entered with PHHICH pointing to a table of origin offsets
; for the arm in question. This table contains the X,Y and Z offsets of the
; arm origin, as three floating-pt numbers.
SSETUP: MOV PWHICH,R5 ;Set up pointer to arm constants
MOV OX(R0),OXHOLD ;COPY 1ST PART OF FLOATING-PT NUMBER
MOV OX+2(R0),OXHOLD+2 ;AND 2ND PART
MOV OY(R0),OYHOLD
MOV OY+2(R0),OYHOLD+2
MOV OZ(R0),OZHOLD
MOV OZ+2(R0),OZHOLD+2
MOV AX(R0),AXHOLD ;SAVE THE A VECTOR ALSO
MOV AX+2(R0),AXHOLD+2 ; AND NEGATE X AND Y COMPONENTS
MOV AY(R0),AYHOLD
MOV AY+2(R0),AYHOLD+2
MOV AZ(R0),AZHOLD
MOV AZ+2(R0),AZHOLD+2
CMP R5,#GCON ;IS IT THE GREEN ARM?
BNE 5$ ;IF NOT (RED ARM) DON'T ROTATE X-Y AXES.
NEGF OXHOLD ;NEGATE TO ACCOUNT FOR 180 DEG ROTATION
NEGF OYHOLD
NEGF AXHOLD
NEGF AYHOLD
LDF PX(R0),AC0 ;GET X COORDINATE OF POSITION VECTOR
NEGF AC0 ;CALCULATE -X + X0
ADDF XCOORD(R5),AC0 ;ADD X OFFSET
STF AC0,PXHOLD ;AND STORE IT
LDF PY(R0),AC0 ;SAME FOR Y COORD
NEGF AC0
ADDF YCOORD(R5),AC0
STF AC0,PYHOLD
BR 10$ ;CONTINUE AND FIND OFFSET Z COORD.
5$: LDF PX(R0),AC0 ;RED ARM: GET X-COORD OF POSITION VECTOR
SUBF XCOORD(R5),AC0 ;CALCULATE X-X0
STF AC0,PXHOLD ;AND SAVE OFFSET X.
LDF PY(R0),AC0 ;SAME FOR Y COORD
SUBF YCOORD(R5),AC0
STF AC0,PYHOLD
10$: LDF PZ(R0),AC0 ;AND Z COORD
SUBF ZCOORD(R5),AC0 ; (EXCEPT FOR Z IT'S Z - Z0)
STF AC0,PZHOLD
RTS PC
; ["PUMSOL" - ROTATION ROUTINES]
;ROT3 rotates both the O and A vectors about (R4) by an amount equal to
;theta = AC2 (and N is thus implicitly rotated too.)
ROT3: PUSH R5
MOV #OXHOLD,R5 ;Rotate O vector
GOSUB ROTATE
MOV #AXHOLD,R5 ;Rotate A
GOSUB ROTATE
POP R5
RTS PC
;ROTATE takes a vector S=(R4) and a vector V=(R5) and an angle theta=AC2.
;It rotates the vector V about the vector S by theta degrees, using Rodrigues'
;formula:
; V' = V cosα + SxV sinα + (V⊗S) (1-cosα) S
;where α is the rotation angle in AC2.
ROTATE: PUSHF AC0
PUSHF AC1
PUSHF AC2 ;Save AC2 since SNCOS garbages it.
PUSH R0
PUSH R1
PUSH R2
MOV R5,R0 ;Copy V into OLDV
MOV #OLDV,R1
GOSUB CPYVEC
MOV R4,R0 ;Get S x V, put into V (result is now forming)
MOV #OLDV,R1
MOV R5,R2
GOSUB XPROD
STF AC2,AC0 ;Put theta in AC0 for SNCOS call
GOSUB SNCOS ;Returns AC0 = sin(theta)
MOV R5,R0 ;Multiply V by sin(theta)
GOSUB SCAMUL
MOV #OLDV,R0 ;Move old V to temp
MOV #TEMPV,R1
GOSUB CPYVEC
STF AC1,AC0 ;Multiply temp (=V) by cos(theta)
MOV #TEMPV,R0
GOSUB SCAMUL
MOV #TEMPV,R0 ;Add temp (= V cos(theta)) to result (in V)
MOV R5,R1
GOSUB ADDVEC
MOV R4,R0 ;Copy S into temp
MOV #TEMPV,R1
GOSUB CPYVEC
MOV R4,R0 ;Find S dot V, put in AC0
MOV #OLDV,R1
GOSUB DOTPRO
NEGF AC1 ;AC1 ← -cos(theta)
ADDF FLT1,AC1 ;AC1 ← 1-cos(theta)
MULF AC1,AC0 ;AC0 ← (S⊗V) * (1-cos(theta))
MOV #TEMPV,R0 ;Multiply temp by above
GOSUB SCAMUL
MOV #TEMPV,R0 ;Add result of above to result
MOV R5,R1
GOSUB ADDVEC ;Result is now rotated V
POP R2
POP R1
POP R0
POPF AC2
POPF AC1
POPF AC0
RTS PC
; ["PUMSOL" - FINDS]
; Given a desired plane the hand must lie in, given by the vector (R4),
; this routine will calculate the vector about which to rotate the goal
; frame (we call it S) and return this vector in (R5). The necessary
; angle of rotation is returned in AC2.
FINDS: PUSHF AC0
PUSHF AC1
PUSH R0
PUSH R1
PUSH R2
LDF AXHOLD,AC0 ;Get X component of A
ABSF AC0 ; (use absolute value for comparison)
COMPF FLT001,AC0 ;Is it less than 0.001?
BLT 5$ ;If not, skip & continue
LDF AYHOLD,AC0 ;Get Y component of A
ABSF AC0 ; (use absolute value for comparison)
COMPF FLT001,AC0 ;Is it less than 0.001?
BGT 50$ ; if so, go do "no rotation" - degenerate
; Figure out which normal to the plane to use: T or T'.
5$: CLRF ZCOORD(R4) ;Make z component of (r,s,0) a zero to be sure.
LDF AXHOLD,AC0 ;Form Ax*Ax in AC0
MULF AC0,AC0
LDF AYHOLD,AC1 ;Put Ay*Ay in AC1
MULF AC1,AC1
ADDF AC1,AC0 ;AC0 ← Ax*Ax + Ay*Ay
GOSUB SQRTF ;Find norm of A's projection on X-Y plane, into AC0
LDF XCOORD(R4),AC1 ;AC1 ← r
MULF AXHOLD,AC1 ;AC1 ← Ax*r
NEGF AC1 ;AC1 ← -Ax*r
LDF YCOORD(R4),AC2 ;AC2 ← s
MULF AYHOLD,AC2 ; Ay*s
SUBF AC2,AC1 ;AC1 ← -Ax*r - Ay*s
DIVF AC0,AC1 ;Divide by norm of A
STF AC1,AC0 ;Put result in AC0 for ACOS
GOSUB ACOS ;AC0 ← acos((-r*ax-s*ay)/normA)
CLR R2 ;Use R2 to indicate if we negated T.
COMPF FLT90,AC0 ;Is 90 ≤ acos(...)? If so, skip & use T
BLE 20$ ;But if acos(...) < 90 then set T ← T'
NEGF XCOORD(R4) ; by negating r and s.
NEGF YCOORD(R4)
INC R2 ;Indicate we negated T, so we can fix it later.
; Now we know which T we're going to use. Find vector S and rotation angle.
20$: MOV R4,R0 ;Copy T into J
MOV #HOLDJ,R1
GOSUB CPYVEC
MOV R4,R0 ;Find T⊗A, result ==> AC0
MOV #AXHOLD,R1
GOSUB DOTPRO
TST R2 ;Did we negate T before?
BEQ 22$ ; no - continue
NEGF XCOORD(R4) ; yes- fix it up.
NEGF YCOORD(R4)
22$: MOV #HOLDJ,R0 ;Multiply J by -T⊗A
NEGF AC0
GOSUB SCAMUL
MOV #AXHOLD,R0 ;Now add A to result. Result is then
MOV #HOLDJ,R1 ; J = A - (T⊗A)T
GOSUB ADDVEC
MOV #HOLDJ,R0 ;Make J a unit vector
GOSUB UNITIZ
MOV #HOLDJ,R0 ;Get ready to find theta. Find J ⊗ A, ==> AC0
MOV #AXHOLD,R1
GOSUB DOTPRO
GOSUB ACOS ;AC0 ← acos(J⊗A) = theta
STF AC0,AC2 ;Save rotation angle (to return)
MOV #AXHOLD,R0 ;Now find S = A x J. Store into (R5)
MOV #HOLDJ,R1
MOV R5,R2
GOSUB XPROD
;Now if the vector S is zero, don't do any rotations
MOV R5,R0 ;Get dot product of S with itself
MOV R5,R1 ; to form length↑2 of vector
GOSUB DOTPRO ;AC0 ← S⊗S
COMPF STHR,AC0 ;Is Threshold > length ?
BGT 50$ ;If so, go do "no rotation" case. Else continue
MOV R5,R0 ;Make S a unit vector
GOSUB UNITIZ
BR 100$ ;exit
50$: MOV #AXHOLD,R0 ;We have A almost vertical. So we don't rotate it.
MOV R5,R1 ;Just copy A into S
GOSUB CPYVEC
CLRF AC2 ;Angle to rotate = 0.
100$: POP R2
POP R1
POP R0
POPF AC1
POPF AC0
RTS PC
; ["PUMSOL" - GET1]
;Called with R4 pointing to the vector (r,s) along which the axis of joint 2
;must lie. Angle 1 is computed as arctan(s,r)-90.
;FIX - When the 6-axis arm is used, delete the first part of this code and
;let the whole thing run.
GET1: LDF YCOORD(R4),AC0 ;AC0 ← S
LDF XCOORD(R4),AC1 ;AC1 ← R
JSR PC,ATAN2 ;AC0 ← ARCTAN(S,R)
SUBF FLT90,AC0 ;OFFSET RESULT BY 90 DEGREES.
RTS PC
;GET1: LDF PXHOLD,AC0 ;LOAD AC0 WITH PX
MULF AC0,AC0 ;AC0 ← PX*PX
LDF PYHOLD,AC1 ;AC1 ← PY
MULF AC1,AC1 ;AC1 ← PY*PY
ADDF AC1,AC0 ;AC0 ← PX↑2 + PY↑2
ABSF AC0 ;AC0 IS NOW R↑2
LDF D3,AC1 ;AC1 ← D3
MULF AC1,AC1 ;AC1 ← D3↑2
SUBF AC1,AC0 ;AC0 ← R↑2 - D3↑2
SQRFIX AC0 ;IF IT'S NEGATIVE BUT NOT TOO MUCH, MAKE IT ZERO.
CHECKF AC0 ;IF THIS IS NEGATIVE, WE'RE IN TROUBLE
BGE 1$ ;IF OK, CONTINUE
BIS #JT1,R3 ;ELSE SOLUTION IS INVALID FOR JOINT 1
RTS PC ;RETURN
1$: JSR PC,SQRTF ;FIND SQRT: AC0 ← SQRT(R↑2 + D3↑2)
STF AC0,TEMP1 ;STORE IN TEMP LOC. TEMP1←SQRT(...)
LDF PYHOLD,AC0 ;AC0 ← PY
LDF PXHOLD,AC1 ;AC1 ← PX
JSR PC,ATAN2 ;AC0 ← ARCTAN(PY,PX)
STF AC0,TRY1 ;TRY1 ← ARCTAN(PY,PX) (1ST PART OF RESULT)
STF AC0,TRY2 ;TRY2 ← ARCTAN(PY,PX) (1ST PART OF RESULT)
LDF TEMP1,AC1 ;AC1 ← SQRT(...) DENOMINATOR OF ARCTAN.
LDF D3,AC0 ;AC0 ← D3
JSR PC,ATAN2 ;FIND ARCTAN(D3, SQRT(...))
LDF TRY1,AC2 ;AC2 ← SOLUTION SO FAR
SUBF AC0,AC2 ;AC2 ← FINISHED SOL'N (LEFT-HANDED)
STF AC2,TRY1 ;TRY1 ← LEFT-HANDED SOL'N
LDF TEMP1,AC1 ;NOW CALCULATE RIGHT-HANDED SOLUTION
NEGF AC1 ; (THAT HAS NEGATIVE SQUARE ROOT)
LDF D3,AC0 ;RELOAD D3 INTO NUMERATOR FOR ARCTAN CALL
JSR PC,ATAN2 ;FIND ARCTAN (D3,-SQRT(...))
LDF TRY2,AC2 ;AC2 ← RIGHT-HANDED SOL'N SO FAR
SUBF AC0,AC2 ;AC2 ← FINISHED SOL'N (RIGHT-HANDED)
STF AC2,TRY2 ;TRY2 ← RIGHT-HANDED SOL'N
LDF TRY1,AC0 ;NOW SEE WHICH IS CLOSER TO CURRENT JT 1 ANGLE
LDF CUR1,AC1 ;PUT CURRENT JT 1 ANGLE IN AC1
JSR PC,DIST ;CALCULATE DIST, PUT IN AC2
STF AC2,AC3 ;AC3 ← DIST. BTW. TRY1 AND CURRENT
LDF TRY2,AC0 ;PUT SECOND SOLUTION IN AC0 FOR DIST. CALCULATION
JSR PC,DIST
COMPF AC3,AC2 ;SEE WHICH IS THE CLOSER SOLUTION
BLE 5$ ;IF TRY1 IS CLOSER THAN TRY2, BR
LDF TRY1,AC1 ;TRY1 WAS FARTHER THEN TRY2. EXCHANGE THEM
LDF TRY2,AC2
STF AC1,TRY2
STF AC2,TRY1
5$: LDF TRY1,AC0 ;SET RESULT IN AC0. ASSUME CLOSE SOLUTION
TST CLOSE1 ;THEN CHECK IF THIS IS RIGHT.
BNE 10$ ;IF OK, EXIT
LDF TRY2,AC0 ;WANT FAR SOLUTION, SO USE TRY2
10$: MOV #TH1,R5 ;WHICH JOINT TO NORMALIZE
JSR PC,NRMLIZ ;NORMALIZE ANGLE TO BE IN RANGE [0,360)
RTS PC
; ["PUMSOL" - GET3]
; THIS ROUTINE YIELDS TWO ANGLES FOR THETA3: TRY1 AND TRY2. EACH OF THESE
; ANGLES PRODUCES A DIFFERENT ANGLE FOR THETA2. WE PICK THE ANGLE FOR THETA2
; WHICH IS CLOSER (OR FARTHER) FROM THE CURRENT ANGLE, AND USING THIS CHOICE,
; SAVE THE CORRESPONDING ANGLE FOR THETA3.
GET3: LDF @TH1(R1),AC0 ;AC0 ← THETA1
JSR PC,SNCOS ;AC0 ← SIN(THETA1), AC1 ← COS(THETA1)
STF AC0,SIN1 ;STORE SIN(THETA1) ≡ SIN1
STF AC1,COS1 ;STORE COS(THETA1) ≡ C1
MULF PXHOLD,AC1 ;AC1 ← C1*PX
MULF PYHOLD,AC0 ;AC0 ← SIN1*PY
ADDF AC0,AC1 ;AC1 ← C1*PX + SIN1*PY = F11P
STF AC1,F11P ;SAVE F11P
MULF AC1,AC1 ;AC1 ← F11P↑2
LDF PZHOLD,AC0 ;AC0 ← PZ
MULF AC0,AC0 ;AC0 ← PZ↑2
ADDF AC0,AC1 ;WE'RE FORMING THE SUM F11P↑2 + F12P↑2
LDF D4,AC0 ;AC0 ← D4
MULF AC0,AC0 ;AC0 ← D4↑2
STF AC0,AC2 ;AC2 IS FORMING THE SUM A3↑2 + D4↑2
SUBF AC0,AC1 ;AC1 ← F11P↑2 + F12P↑2 - D4↑2
LDF A3,AC0 ;AC0 ← A3
MULF AC0,AC0 ;AC0 ← A3↑2
ADDF AC0,AC2 ;AC2 ← D4↑2 + A3↑2
SUBF AC0,AC1 ;AC1 ← ... - A3↑2
LDF A2,AC0 ;AC0 ← A2
MULF AC0,AC0 ;AC0 ← A2↑2
MULF AC0,AC2 ;AC2 ← A2↑2 * (D4↑2 + A3↑2)
SUBF AC0,AC1 ;AC1 ← F11P↑2 + F12P↑2 - D4↑2 - A3↑2 - A2↑2
STF AC1,TEMP2 ;SUM IS D IN THE WRITEUP -- SAVE D IN TEMP2
MULF FLT4,AC2 ;AC2 IS NOW E IN WRITEUP
MULF AC1,AC1 ;AC1 ← D↑2
SUBF AC1,AC2 ;AC2 ← E - D↑2
STF AC2,AC0 ;AC0 ← E-D↑2
SQRFIX AC2 ;IF AC2 IS NEGATIVE BUT NOT TOO MUCH, MAKE IT 0.
CHECKF AC2 ;SEE IF IT'S LESS THAN ZERO
BGE 5$ ;IF OK, BR
BIS #JT3,R3 ;OTHERWISE JOINT 3 SOL'N IS NO GOOD
RTS PC ;RETURN TO CALLER.
5$: JSR PC,SQRTF ;PUT SQRT(E-D↑2) BACK INTO AC0
STF AC0,TEMP1 ;TEMP1 ← SQRT(E-D↑2)
LDF A3,AC0 ;AC0 ← A3
LDF D4,AC1 ;AC1 ← D4
NEGF AC1 ;AC1 ← -D4
JSR PC,ATAN2 ;AC0 ← ARCTAN(A3, -D4)
STF AC0,TRY1 ;STORE ARCTAN AS 1ST PART OF RESULT
STF AC0,TRY2 ;STORE ARCTAN AS 1ST PART OF RESULT
LDF TEMP2,AC0 ;AC0 ← D (FROM TEMP2)
LDF TEMP1,AC1 ;AC1 ← SQRT(E-D↑2)
JSR PC,ATAN2 ;PUT ARCTAN(D,SQRT(...)) INTO AC0
NEGF AC0 ;AC0 ← -ATAN(...)
ADDF TRY1,AC0 ;AC0 ← THE "ABOVE" SOLUTION
MOV #TH3,R5 ;NORMALIZE JOINT 3 ANGLE
JSR PC,NRMLIZ ;PUT ANGLE IN RANGE
STF AC0,TRY1 ;STORE ABOVE SOL'N IN TRY1
LDF TEMP1,AC1 ;NOW DO THE "BELOW" SOLUTION, WHICH HAS
NEGF AC1 ;THE SQUARE ROOT NEGATED.
LDF TEMP2,AC0 ;LOAD NUMERATOR (D)
JSR PC,ATAN2 ;GET ARCTAN
NEGF AC0 ;AC0 ← -ATAN(...)
ADDF TRY2,AC0 ;AC0 ← THE COMPLETE "BELOW" SOLUTION.
MOV #TH3,R5
JSR PC,NRMLIZ ;NORMALIZE THE RESULT
STF AC0,TRY2 ;STORE BELOW SOL'N IN TRY2
RTS PC ;BACK TO CALLER
; ["PUMSOL" - GET2]
GET2: LDF TRY1,AC0 ;PUT 1ST TRY FOR THETA3 INTO AC0
JSR PC,CALC2 ;FIGURE OUT CORRESPONDING THETA2.
STF AC0,ANG2T1 ;STORE IN ANGLE2, TRY1
LDF TRY2,AC0 ;DO THE SAME FOR THE OTHER ANGLE
JSR PC,CALC2
STF AC0,ANG2T2 ;STORE 2ND TRY FOR ANGLE 2
LDF CUR2,AC1 ;AC1 ← CURRENT THETA2
JSR PC,DIST ;AC2 ← ANGLE BTW. TRY#2 AND CURRENT
STF AC2,AC3 ;AC3 ← 2ND DISTANCE
LDF ANG2T1,AC0 ;NOW FIND DISTANCE FOR 1ST TRY
JSR PC,DIST ;AC2 ← ANGLE BTW. TRY#1 AND CURRENT
COMPF AC2,AC3 ;COMP DISTANCE1 TO DISTANCE2
BLE 5$ ;IF 1ST IS NOT GREATER THAN 2ND, OK & SKIP
LDF TRY1,AC1 ;2ND WAS CLOSER THAN 1ST. EXCHANGE TRY1 AND TRY2.
LDF TRY2,AC2
STF AC1,TRY2
STF AC2,TRY1
LDF ANG2T1,AC1 ;ALSO EXCHANGE TRIES FOR ANGLE 2.
LDF ANG2T2,AC2
STF AC1,ANG2T2
STF AC2,ANG2T1
5$: LDF TRY1,AC0 ;ASSUME WE WANT THE CLOSE ANGLE
STF AC0,@TH3(R1) ;SO STORE IT FIRST
LDF ANG2T1,AC0 ;PUT ANGLE2 IN AC0
TST CLOSE2 ;DID WE REALLY WANT THE CLOSE ONE FOR ANGLE 2?
BNE 10$ ;IF SO, EXIT
LDF TRY2,AC1 ;WANTED FAR ANGLE, SO USE IT
STF AC1,@TH3(R1)
LDF ANG2T2,AC0
10$: RTS PC ;TO CALLER
; WE ASSUME THETA3 IS IN AC0, AND UPON EXIT, AC0 CONTAINS THETA2.
CALC2: STF AC0,@TH3(R1) ;TEMPORARILY SAVE ATTEMPT AT ANGLE 3.
JSR PC,SNCOS ;AC0 ← SIN(THETA3) AC1 ← COS(THETA3)
STF AC0,SIN3 ;SAVE THE SINE AND COSINE
STF AC1,C3
MULF A2,AC1 ;AC1 ← A2*C3
ADDF A3,AC1 ;AC1 ← A2*C3 + A3 ≡ W1 (W1 WILL STAY IN AC1 A WHILE)
MULF A2,AC0 ;AC0 ← A2*S3
ADDF D4,AC0 ;AC0 ← D4 + A2*S3 ≡ W2
STF AC0,AC2 ;AC2 ← W2 (W2 WILL STAY IN AC2 FOR A WHILE)
LDF F11P,AC0 ;AC0 ← F11P
MULF AC2,AC0 ;AC0 ← W1*F11P
LDF PZHOLD,AC3 ;AC3 ← PZ
MULF AC1,AC3 ;AC3 ← W1*PZ
SUBF AC3,AC0 ;AC0 ← W2*F11P - W1*PZ
MULF F11P,AC1 ;AC1 ← W1*F11P
MULF PZHOLD,AC2 ;AC2 ← W2*PZ
ADDF AC2,AC1 ;AC1 ← W1*F11P + W2*PZ
JSR PC,ATAN2 ;AC0 ← ARCTAN(W2*F11P-W1*PZ, W1*F11P+W2*PZ)
SUBF @TH3(R1),AC0 ;AC0 ← THETA23 - THETA3 = THETA2
MOV #TH2,R5 ;NORMALIZE JOINT 2 ANGLE
JSR PC,NRMLIZ ;NORMALIZE THE RESULT (THETA2)
RTS PC ;TO CALLER
; ["PUMSOL" - GET4]
; FIX THIS IF 6 AXES ARE USED.
GET4: LDF @TH2(R1),AC0 ;AC0 ← THETA2
ADDF @TH3(R1),AC0 ;AC0 ← THETA2 + THETA3
JSR PC,SNCOS ;AC0 ← SIN(T2+T3) AC1 ← COS(T2+T3)
STF AC0,S23 ;STORE SINE
STF AC1,C23 ;AND COSINE
LDF COS1,AC1 ;AC1 ← C1
MULF AYHOLD,AC1 ;AC1 ← C1*AY
LDF SIN1,AC2 ;AC2 ← SIN1
MULF AXHOLD,AC2 ;AC2 ← SIN1*AX
SUBF AC2,AC1 ;AC1 ← -SIN1*AX + C1*AY ≡ F13A
STF AC1,F13A ;STORE RESULT -- THIS IS F13A
LDF AXHOLD,AC2 ;AC2 ← AX
MULF COS1,AC2 ;AC2 ← C1*AX
LDF SIN1,AC1 ;AC1 ← SIN1
MULF AYHOLD,AC1 ;AC1 ← SIN1*AY
ADDF AC1,AC2 ;AC2 ← C1*AX + SIN1*AY ≡ F11A
STF AC2,F11A ;STORE THIS RESULT FOR LATER USE
LDF C23,AC1 ;AC1 ← C23
MULF AC1,AC2 ;AC2 ← C23*F11A
LDF AZHOLD,AC1 ;AC1 ← AZ
MULF S23,AC1 ;AC1 ← S23*AZ
STF AC1,S23AZ ;STORE INTERMEDIATE RESULT
SUBF AC1,AC2 ;AC2 ← C23*F11A - S23*AZ
STF AC2,T4BOT ;KEEP THIS INTERMEDIATE FOR USE IN GET5.
LDF F13A,AC0 ;GET READY FOR ARCTAN: AC0 ← F13A
STF AC2,AC1 ;AC1 ← BOTTOM OF ARCTAN EXPR
JSR PC,ATAN2 ;PUT ARCTAN (F13A,T4BOT) INTO AC0
MOV #TH4,R5 ;NORMALIZE ANGLE 4
JSR PC,NRMLIZ ;RESULT (AC0) IS THETA4 -- NORMALIZE IT
CLRF AC0 ;*** THETA4=0 ALWAYS *** FIX FOR 6-AXIS ARM
RTS PC
; ["PUMSOL" - GET5]
GET5: LDF @TH4(R1),AC0 ;GET READY TO FIND SIN AND COS OF THETA4
JSR PC,SNCOS ;AC0 ← SIN(THETA4) AC1 ← COS(THETA4)
STF AC0,SIN4 ;STORE SIN AND COS OF THETA4
STF AC1,C4
MULF F13A,AC0 ;AC0 ← S4*F13A
MULF T4BOT,AC1 ;AC1 ← C4*T4BOT
ADDF AC1,AC0 ;AC0 ← C4*T4BOT + S4*F13A
LDF S23,AC1 ;AC1 ← S23
MULF F11A,AC1 ;AC1 ← S23*F11A
LDF C23,AC2 ;AC2 ← C23
MULF AZHOLD,AC2 ;AC2 ← C23*AZ
ADDF AC2,AC1 ;AC1 ← S23*F11A + C23*AZ
JSR PC,ATAN2 ;AC0 ← ARCTAN(...,...) ≡ THETA5
MOV #TH5,R5 ;TO NORMALIZE ANGLE 5
JSR PC,NRMLIZ ;NORMALIZE THE RESULT
COMPF FLT180,AC0 ;COMPARE 180 TO THETA5. IF THETA5>180,WE'RE NOT DONE
;(NOTE IF α>180, IN THE RANGE (-180,180), α<0)
BGE 10$ ;IF 180 ≥ THETA5, OK, SO EXIT
STF AC0,AC3 ;STORE THETA5 AWAY SO WE CAN RESTORE IT LATER.
LDF @TH4(R1),AC0 ;IF THETA5>180, ADD 180 TO THETA4
ADDF FLT180,AC0 ;AC0 ← THETA4 + 180
MOV #TH4,R5
JSR PC,NRMLIZ ;NORMALIZE NEW THETA4
STF AC0,@TH4(R1) ;SAVE NEW THETA4
NEGF SIN4 ;WE MUST NEGATE OLD S4 AND C4
NEGF C4 ; SINCE SIN(α+180)=-SIN(α) AND SAME FOR COS
STF AC3,AC0 ;PUT THETA5 BACK INTO AC0
10$: RTS PC ;RETURN TO CALLER
; ["PUMSOL" - GET6]
GET6: LDF @TH5(R1),AC0 ;AC0 ← THETA5
JSR PC,SNCOS ;AC0 ← SIN(THETA5) AC1 ← COS(THETA5)
STF AC0,SIN5 ;STORE SIN(THETA5)
STF AC1,C5 ;STORE COS(THETA5)
LDF SIN1,AC0 ;AC0 ← SIN1
MULF OYHOLD,AC0 ;AC0 ← SIN1*OY
LDF COS1,AC1 ;AC1 ← C1
MULF OXHOLD,AC1 ;AC1 ← C1*OX
ADDF AC1,AC0 ;AC0 ← C1*OX + SIN1*OY ≡ F11O
STF AC0,F11O ;STORE F11O
LDF SIN1,AC0 ;AC0 ← SIN1
MULF OXHOLD,AC0 ;AC0 ← SIN1*OX
LDF COS1,AC1 ;AC1 ← C1
MULF OYHOLD,AC1 ;AC1 ← C1*OY
SUBF AC0,AC1 ;AC1 ← C1*OY - SIN1*OX
STF AC1,F13O ;THIS IS F13O, STORE IT.
LDF C23,AC0 ;AC0 ← C23
MULF F11O,AC0 ;AC0 ← C23*F11O
LDF S23,AC1 ;AC1 ← S23
MULF OZHOLD,AC1 ;AC1 ← S23*OZ
SUBF AC1,AC0 ;AC0 ← C23*F11O - S23*OZ
STF AC0,PART1 ;THIS IS A MAJOR PART OF THE RESULT, SAVE IT.
MULF C4,AC0 ;AC0 ← C4*PART1
LDF SIN4,AC1 ;AC1 ← S4
MULF F13O,AC1 ;AC1 ← S4*F13O
ADDF AC1,AC0 ;AC0 ← C4*PART1 + S4*F13O
MULF C5,AC0 ;AC0 ← C5*(.... + ....)
LDF S23,AC1 ;AC1 ← S23
MULF F11O,AC1 ;AC1 ← S23*F11O
LDF C23,AC2 ;AC2 ← C23
MULF OZHOLD,AC2 ;AC2 ← C23*OZ
ADDF AC2,AC1 ;AC1 ← S23*F11O + C23*OZ
MULF SIN5,AC1 ;AC1 ← S5*(.... + ....)
SUBF AC0,AC1 ;AC1 ← TOP PART OF ARCTAN
STF AC1,AC0 ;KEEP TOP PART IN AC0
LDF PART1,AC1 ;AC1 ← PART1
MULF SIN4,AC1 ;AC1 ← S4*PART1
LDF C4,AC2 ;AC2 ← C4
MULF F13O,AC2 ;AC2 ← C4*F13O
SUBF AC1,AC2 ;AC2 ← C4*F13O - S4*PART1
STF AC2,AC1 ;THIS IS DENOMINATOR FOR ARCTAN -- KEEP IN AC1
JSR PC,ATAN2 ;AC0 ← ARCTAN (TOP,BOTTOM)
MOV #TH6,R5 ;TO NORMALIZE ANGLE 6
JSR PC,NRMLIZ ;NORMALIZE RESULT (THIS IS THETA6)
RTS PC ;TO CALLER
; ["PUMSOL" - FIX4]
; This routine checks for:
; 1. |theta5| = 0. If this happens, it is a degenerate solution and
; we add theta4 to theta6 and make theta4 = 0.
; 2. |theta4| = 180 degrees. If this is the case, we make theta4 = 0 and
; negate theta5 and rotate theta6 accordingly.
; 3. We don't confine theta6 to be in the range [-180,180], but instead
; correct it so that it may fall in its true range, [-266,266], based
; upon its current angle.
FIX4: LDF @TH5(R1),AC0 ;AC0 ← THETA5.
ABSF AC0 ;USE |THETA5|
COMPF FLT01,AC0 ;COMPARE TO 0.01 (ACCOUNT FOR ROUNDING ERRORS)
BLT 5$ ;IF 0.01 < THETA5, EXIT. BUT IF NOT, THEN
LDF @TH6(R1),AC0 ;AC0 ← THETA6
ADDF @TH4(R1),AC0 ;AND ADD THETA4
MOV #TH6,R5 ;NORMALIZE NEW THETA6 = THETA6 + THETA4
JSR PC,NRMLIZ
STF AC0,@TH6(R1) ;STORE BACK
CLRF @TH4(R1) ;PUT ZERO INTO THETA4
BR 10$ ;EXIT - SINCE THETA4 IS NOW ZERO.
5$: LDF @TH4(R1),AC0 ;AC0 ← THETA4. IF THIS IS 180, WE'RE NOT DONE YET.
ABSF AC0 ;MAY BE -180 TOO.
COMPF FLT179,AC0 ;ACCOUNT FOR ROUNDING ERRORS, MAY NOT = 180
BGE 10$ ;IF 179 ≥ |THETA4|, DO NOTHING.
ADDF @TH6(R1),AC0 ;OTHERWISE ADD THETA6 TO THETA4
MOV #TH6,R5 ;NORMALIZE NEW THETA6 = THETA6 + THETA4
JSR PC,NRMLIZ
STF AC0,@TH6(R1) ;STORE BACK
CLRF @TH4(R1) ;PUT ZERO INTO THETA4
NEGF @TH5(R1) ;NEGATE THETA5
10$: LDF @TH6(R1),AC0 ;Do the 3rd check. Get calculated jt6 angle
SUBF @TH6(R2),AC0 ;Find the difference |dest - current|
ABSF AC0
COMPF FLT180,AC0 ;Is the difference ≤ 180? If so, leave jt6 alone
BGE 100$ ;if 180 ≥ |diff|, exit
LDF @TH6(R1),AC0 ;Need to fix Jt6. Put it in AC0.
CHECKF AC0 ;Is dest negative?
BLT 15$ ;if so, add 360 to it
SUBF FLT360,AC0 ;if positive, subtract 360 from it
BR 20$
15$: ADDF FLT360,AC0
20$: STF AC0,@TH6(R1) ;Store updated Jt6 back into result vector
100$: RTS PC ;TO CALLER
; ["PUMSOL" - OFSETS]
; A routine to account for the length of the tool -- we offset the solution
; backwards along the tool Z axis (the A vector) by an amount equal to TOOLEN.
OFSETS: LDF AXHOLD,AC0 ;AC0 ← AX
MULF TOOLEN,AC0 ;AC0 ← AX*TOOLLENGTH
LDF PXHOLD,AC1 ;AC1 ← CURRENT PX
SUBF AC0,AC1 ;AC1 ← PX - AX*TOOLLENGTH
STF AC1,PXHOLD ;STORE OFFSET PX
LDF AYHOLD,AC0 ;AC0 ← AY
MULF TOOLEN,AC0 ;AC0 ← AY*TOOLLENGTH
LDF PYHOLD,AC1 ;AC1 ← PY
SUBF AC0,AC1 ;AC1 ← PY - AY*TOOLLENGTH
STF AC1,PYHOLD ;THIS IS OFFSET PY
LDF AZHOLD,AC0 ;AC0 ← AZ
MULF TOOLEN,AC0 ;AC0 ← AZ*TOOLLENGTH
LDF PZHOLD,AC1 ;AC1 ← PZ
SUBF AC0,AC1 ;AC1 ← PZ + AZ*TOOLLENGTH
STF AC1,PZHOLD ;THIS IS OFFSET PZ
RTS PC
; ["PUMSOL" - ANGLE MANIPULATION ROUTINES]
; NRMLIZ normalizes the angle in AC0 - it puts it in the correct range for
; that joint. The lower bound for the range (which is [lobound, lobound+360])
; is found in the table LOLIM.
; Call this routine with angle in AC0, joint offset in R5 (e.g. MOV #TH1,R5)
; R5 is altered!
; Returns with normalized angle in AC0.
NRMLIZ: PUSH R4
PUSHF AC1
ASL R5 ;MULT BY 2 TO GET OFFSET INTO 2-WORD LENGTH TABLES
LDF LOLIM(R5),AC1 ;GET LOW LIMIT OF RANGE FOR ANGLE
3$: COMPF AC0,AC1 ;IS ANGLE ≥ LOWLIMIT? IF SO, DON'T CHANGE IT
BGE 5$
ADDF FLT360,AC0 ;ADD 360 TO ANGLE
BR 3$ ;MAY STILL BE OUT OF RANGE -- KEEP TESTING.
5$: ADDF FLT360,AC1 ;PUT UPPER BOUND INTO AC1
7$: COMPF AC0,AC1 ;SEE IF IT'S BIGGER THAN RANGE
BLT 10$ ;IF 360 < ANGLE, EXIT
SUBF FLT360,AC0 ;WAS TOO BIG, SUBTRACT 360
BR 7$ ;IT MAY STILL BE TOO BIG, SO KEEP TESTING.
10$: POPF AC1
POP R4
RTS PC
; CHKJNT SEES IF A JOINT IS WITHIN ITS STOP LIMITS. IF NOT, THE APPROPRIATE
; BIT IN R3 IS SET TO INDICATE THAT IT IS OUT OF RANGE. CALLED WITH JOINT
; OFFSET IN R5 (E.G. MOV #TH1,R5) AND ANGLE IN AC0.
; R5 IS ALTERED!
CHKJNT: ASL R5 ;MULT BY 2 FOR OFFSET INTO FLTING-PT TABLE
COMPF LOSTOP(R5),AC0 ;IS LOW STOP > ANGLE?
BGT 5$ ;IF SO, ANGLE IS OUT OF BOUNDS - SET FLAG
COMPF HISTOP(R5),AC0 ;IS HIGH STOP < ANGLE?
BGE 10$ ;IF NOT, WE'RE OK.
5$: ASH #-2,R5 ;DIVIDE R5 BY 4 (GIVES 0,1,2,3,4)
PUSH R4 ;SAVE OLD R4
MOV #1,R4 ;SET TO 1 TO INDICATE JOINT 1 NO GOOD
ASH R5,R4 ;SHIFT LEFT BY JT PLACES. YIELDS JT# WHICH IS BAD
BIS R4,R3 ;SET APPROPRIATE BIT IN R3, THE ERROR FLAG.
POP R4
10$: RTS PC ;TO CALLER
; DIST CALCULATES THE DISTANCE IN DEGREES BETWEEN THE ANGLES IN AC0 AND AC1
; AND PUTS THE RESULT INTO AC2.
DIST: STF AC0,AC2 ;AC2 ← ANGLE1
SUBF AC1,AC2 ;FORM THE DIFFERENCE
ABSF AC2 ;TAKE ABSOLUTE VALUE OF DIFF.
COMPF FLT360,AC2 ;MAKE SURE DIFF IS < 360. IS 360 > DIFF?
BGT 3$ ;IF SO, CONTINUE -- WE'RE OK
SUBF FLT360,AC2
3$: COMPF FLT180,AC2 ;IS 180 ≥ DIFF?
BGE 5$ ;IF SO, EXIT
NEGF AC2 ;MAKE AC2 INTO 360-AC2.
ADDF FLT360,AC2
5$: RTS PC
; ["PUMSOL" - VECTOR MANIPULATION ROUTINES]
; In the following, all vectors contain 3 components. A vector which is
; pointed to by a register, say R0, is referred to by "(R0)".
;ADDVEC adds the vector (R0) to (R1).
ADDVEC: PUSHF AC0
PUSH R5
MOV #3,R5 ;Vector has 3 components
1$: LDF (R1),AC0 ;Get component of 2nd vector
ADDF (R0)+,AC0 ;Add component of 1st to it
STF AC0,(R1)+ ; and store back
SOB R5,1$
POP R5
POPF AC0
RTS PC
;DOTPRO finds the dot product of (R0) and (R1) and returns it in AC0.
DOTPRO: PUSHF AC1
PUSH R5
MOV #3,R5
CLRF AC0 ;Clear the result
1$: LDF (R0)+,AC1 ;Get component of 2nd vector
MULF (R1)+,AC1 ;and multiply by component of 1st.
ADDF AC1,AC0 ;Add to sum
SOB R5,1$
POP R5
POPF AC1
RTS PC
;CPYVEC copies the vector (R0) into (R1).
CPYVEC: PUSH R5
MOV #3,R5
1$: MOV (R0)+,(R1)+ ;Get 1st part of floating-pt number & copy
MOV (R0)+,(R1)+ ;copy 2nd half of floating-pt number
SOB R5,1$
POP R5
RTS PC
;SCAMUL performs a scalar multiply: multiplies the vector (R0) by AC0.
SCAMUL: PUSHF AC1
PUSH R5
MOV #3,R5
1$: LDF (R0),AC1 ;Get component
MULF AC0,AC1 ;and multiply by the scalar
STF AC1,(R0)+ ;Store back
SOB R5,1$
POP R5
POPF AC1
RTS PC
;XPROD calculates the cross product of (R0) and (R1) and puts it into (R2).
XPROD: PUSHF AC0
PUSHF AC1
LDF YCOORD(R0),AC0 ;AC0 ← Y0
MULF ZCOORD(R1),AC0 ;AC0 ← Y0*Z1
LDF YCOORD(R1),AC1 ;AC1 ← Y1
MULF ZCOORD(R0),AC1 ;AC1 ← Y1*Z0
SUBF AC1,AC0 ;AC0 ← Y0*Z1 - Y1*Z0
STF AC0,XCOORD(R2) ;Store X component of (R0)x(R1)
LDF XCOORD(R0),AC0 ;Similarly for Y component:
MULF ZCOORD(R1),AC0
LDF XCOORD(R1),AC1
MULF ZCOORD(R0),AC1
SUBF AC0,AC1
STF AC1,YCOORD(R2) ;Y component = X1*Z0 - X0*Z1
LDF XCOORD(R0),AC0 ;Now do the Z component
MULF YCOORD(R1),AC0
LDF XCOORD(R1),AC1
MULF YCOORD(R0),AC1
SUBF AC1,AC0
STF AC0,ZCOORD(R2) ;Z component = X0*Y1 - X1*Y0
POPF AC1
POPF AC0
RTS PC
;UNITIZ will unitize the vector (R0), i.e. make it into a unit vector.
UNITIZ: PUSHF AC0
PUSHF AC1
PUSH R5
MOV R0,R1 ;Use DOTPRO to get (x,y,z)⊗(x,y,z) = x*x + y*y + z*z
GOSUB DOTPRO ;AC0 ← x*x + y*y + z*z
SUB #<3*4>,R0 ;Restore R0 to whatever it used to be.
GOSUB SQRTF ;AC0 ← SQRT(X*X + Y*Y + Z*Z) = norm of vector
MOV #3,R5 ;Now go thru & divide (R0) by AC0.
1$: LDF (R0),AC1 ;Put component into AC1
DIVF AC0,AC1 ;Divide by norm
STF AC1,(R0)+ ;and store back
SOB R5,1$
POP R5
POPF AC1
POPF AC0
RTS PC
; ["PUMSOL" - LOCAL DATA]
DATA
;MISC. HOLDING AREAS AND TEMP.VARIABLES:
TRY1: .BLKW 2
TRY2: .BLKW 2
TEMP1: .BLKW 2
TEMP2: .BLKW 2
F11P: .BLKW 2
S23AZ: .BLKW 2
T4BOT: .BLKW 2
F11A: .BLKW 2
F13A: .BLKW 2
F11O: .BLKW 2
F13O: .BLKW 2
CUR1: .BLKW 2 ;CURRENT JOINT 1 ANGLE
CUR2: .BLKW 2
OXHOLD: .BLKW 2 ;FOR HOLDING THE COMPONENTS OF THE VECTORS
OYHOLD: .BLKW 2 ; IN THE GOAL FRAME.
OZHOLD: .BLKW 2
AXHOLD: .BLKW 2
AYHOLD: .BLKW 2
AZHOLD: .BLKW 2
PXHOLD: .BLKW 2
PYHOLD: .BLKW 2
PZHOLD: .BLKW 2
OLDV: .BLKW <3*2> ;TEMPORARY STORAGE FOR ROTATION ROUTINES
TEMPV: .BLKW <3*2>
HOLDJ: .BLKW <3*2>
SQ: .BLKW 2
T1: .BLKW <3*2>
T2: .BLKW <3*2>
SA: .BLKW <3*2>
SB: .BLKW <3*2>
RANG1: .BLKW 2
RANG2: .BLKW 2
PWHICH: .WORD 0 ;POINTER TO ARM CONSTANTS
CLOSE1: .WORD 0 ;NOT USED IN THIS VERSION
CLOSE2: .WORD 0 ;SAME, FOR JOINT 2.
FAR: .WORD 0 ;0=GOT CLOSE SOL'N, ≠0=GOT A FAR SOL'N
STHR: .FLT2 1.0E-6 ;Length↑2 of S must be < this to be called zero.
CODE
;UPDATE - COMPUTES THE ARM TRANSFORM GIVEN THE JOINT ANGLES
;GIVEN THE JOINT ANGLES, THE RESULTING HAND POSITION AND ORIENTATION ARE
;DETERMINED AND STORED IN A GIVEN TRANSFORM "T". THE TRANSFORM IS A 4 BY 4
;MATRIX STORED BY COLUMNS WITH EACH VALUE REPRESENTED IN TABLE COORDINATES.
;NO INITIALIZATION NEEDS TO BE DONE ON THE T SINCE ALL THE ELEMENTS WILL BE
;UPDATED, EVEN THOUGH THE LAST ROW IS ALWAYS 0,0,0,1 . A SAMPLE CALLING
;SEQUENCE FOLLOWS:
;
; MOV #T,R0 ;LOAD TRANSFORM ADDRESS IN R0
; MOV #THETA,R1 ;PTR TO A TABLE CONTAINING POINTERS TO THE
; ; JOINT ANGLES FOR ALL EXISTING ARM JOINTS,
; ; I.E., THE TABLE MUST HAVE 28 ELEMENTS.
; MOV #MECHSM,R2 ;CONSTANT INDICATING WHICH ARM TO USE
; JSR PC,UPDATE ;CALLED USING PC
;
;THE TRANSFORM WILL BE OF THE FOLLOWING FORM:
;
; | T1 T5 T9 T13 |
; | T2 T6 T10 T14 |
; | T3 T7 T11 T15 |
; | 0 0 0 1.0 |
;
;THE PROCEDURE CONSISTS OF GENERATION OF TWO MATRICES T1 AND T2, THE TRANSFORM
;FROM SHOULDER TO WRIST AND FROM WRIST TO HAND RESPECTIVELY, THEN MULTIPLYING
;THE TWO TO GIVE THE DESIRED TRANSFORM.
;
;THIS PROCEDURE MODIFIED ON JUNE 9TH, 1976 TO THE EXTENT THAT THE FIRST
;COL OF T2 IS NOT COMPUTED, AND THUS ONLY THE THIRD THREE COLS OF
;T ARE COMPUTED. THE FIRST COLUMN IS THEN FOUND BY TAKING THE CROSS PRODUCT
;OF THE SECOND AND THIRD COLUMNS.
;
;IF THE BLUE OR YELLOW HAND IS SPECIFIED AS THE MECHANISM, THE HAND OPENING
;POINTED TO BY THE "THETA" ARRAY IS RETURNED IN THE LOCATION POINTED TO BY
;"T". ALL NUMBERS SHOULD BE IN SINGLE PRECISION FLOATING POINT
;REPRESENATATION.
;EXECUTION TIME: 2080 microsecs
;REGISTERS USED:
;
; R0 - T TRANSFORM/LINK NUMBER
; R1 - THETA LIST/ARM CONSTANTS LIST POINTER
; R2 - BLUE/YELLOW ARM FLAG
; AC0,AC1,AC2,AC3,AC4,AC5 GARBAGED
; R0,R1 GARBAGED
;DEFINITIONS:
SN==%0
CS==%1
SN1==%4
CS1==%5
SN2==%0
CS2==%1
SN4==%3
CS4==%4
CS5==%5
; ["UPDATE"- HAND OR T6]
UPDATE: MOV R2,-(SP) ;SAVE REGISTERS
MOV R3,-(SP)
MOV R4,-(SP)
MOV R5,-(SP)
BIT #YELARM+BLUARM+GRNARM+REDARM,R2 ;CHECK IT'S ONE OF THE ARMS
BNE 1$ ;IF IT'S AN ARM, BR
;SECTION TO RETURN HAND OPENINGS
;WHAT IF IT'S A PUMA???
ADD #12.,R1 ;GET POINTER TO YELLOW HAND OPENING
BIT #YELHND,R2 ;CHECK WHICH HAND WE ARE DEALING WITH
BNE .+6 ;SKIP IF ITS THE YELLOW HAND MECH. BIT
ADD #14.,R1 ;ELSE GET THE BLUE HAND POINTER
LDF @(R1),AC0 ;GET THE PREVIOUS HAND OPENING
STF AC0,(R0) ;RETURN THE CORRECT HAND OPENING AND EXIT
BR 3$
;ARM HANDLER
1$: BIT #GRNARM+REDARM,R2 ;IS IT A PUMA??
BEQ 10$ ;IF NOT, GO INTO STANFORD ARM SOL'N
MOV #GCON,R5 ;ASSUME GREEN ARM & SET R5 TO CONSTANT TABLE
ADD #32.,R1 ; POINT R1 TO GREEN ANGLES
BIT #REDARM,R2 ;WAS IT REALLY THE RED ARM??
BEQ 20$ ;IF NOT, BR
MOV #RCON,R5 ;SET R5 TO RED ARM CONSTANTS
ADD #14.,R1 ;POINT TO RED ARM ANGLES.
20$: JSR PC,PUMUPD ;UPDATE PUMA MATRIX
BR 3$ ;RETURN
10$: MOV #YCON,R3 ;ADDR OF YELLOW ARM PHYSICAL CONSTANTS
BIT #YELARM,R2 ;CHECK IF YELLOW OR BLUE ARM
BNE 2$ ;SKIP IF YELLOW ARM
MOV #BCON,R3 ;ELSE GET ADDR OF BLUE ARM CONSTANTS
ADD #14.,R1 ;POINT TO BLUE ARM JOINT ANGLES
2$: CLR R4 ;COMPUTE T0_3 & T3_6: ADD IN BASEX,BASEY
JSR PC,T0336U
MOV #T311,R1 ;RESULT ← T3*T6
MOV #T011,R2
JSR PC,MATMUL
;RESTORE REGISTERS AND EXIT
3$: MOV (SP)+,R5 ;RESTORE REGISTERS
MOV (SP)+,R4
MOV (SP)+,R3
MOV (SP)+,R2
RTS PC ;EXIT
;END OF "UPDATE"
; ---> PUMUPD < --- THE PUMA UPDATE ROUTINE
; "PUMUPD" is a routine which, given a vector of six joint angles for the PUMA,
; will return a 4 x 4 matrix which contains the position and orientation of
; the hand.
; ARGUMENTS:
; R0 - Points to a matrix which will contain, upon exit, the Cartesian
; coordinates and orientation (Euler angles) of the manipulator.
; This will be stored in column-major order, the same as the matrix
; described in "solve".
; R1 - Points to a vector, 6 words long, each word of which points to
; a single-precision floating-point number which is an angle in
; degrees. The 6 angles thus referenced are assumed to be the
; joint angles of the arm.
; R5 - Points to the arm constants for this manipulator, i.e. either
; RCON or GCON. These are used to get the offset of the base of
; the arm in AL's world.
; REGISTERS USED:
; R0,R1,R5 For passing arguments. They are not changed.
; AC0,AC1,AC2: Destroyed.
; [CONTINUATION OF PUMUPD: THE MAIN PART]
PUMUPD: MOV R5,PWHICH ;SAVE ADDR OF CONSTANTS TABLE FOR THIS ARM
JSR PC,DOTRIG ;FIGURE OUT SINES & COSINES NEEDED
JSR PC,GETN ;CALCULATE & STORE N VECTOR
JSR PC,GETO ;STORE O (ORIENTATION) VECTOR
JSR PC,GETA ;STORE THE A (APPROACH) VECTOR
JSR PC,GETP ;LAST, THE P (POSITION) VECTOR
JSR PC,OFSETW ;OFFSET RESULT TO ACCT. FOR LENGTH OF TOOL.
;ALSO ACCOUNT FOR ROTATION & OFFSET OF ORIGIN
RTS PC ;TO CALLER
; [CONTINUATION OF PUMUPD: DOTRIG]
; Retreive the joint angles from the vector pointed to by R1, and calculate
; sine & cosine for them all.
DOTRIG: LDF @TH1(R1),AC0 ;AC0 ← THETA1
JSR PC,SNCOS ;AC0 ← SIN(THETA1), AC1 ← COS(THETA1)
STF AC0,SIN1 ;STORE SIN1=SIN(THETA1)
STF AC1,COS1 ;STORE C1=COS(THETA1)
LDF @TH2(R1),AC0 ;DO THE SAME FOR THE OTHER ANGLES
JSR PC,SNCOS
STF AC0,SIN2
STF AC1,COS2
LDF @TH4(R1),AC0
JSR PC,SNCOS
STF AC0,SIN4
STF AC1,C4
LDF @TH5(R1),AC0
JSR PC,SNCOS
STF AC0,SIN5
STF AC1,C5
LDF @TH6(R1),AC0
JSR PC,SNCOS
STF AC0,SIN6
STF AC1,C6
LDF @TH2(R1),AC0 ;AC0 ← THETA2
LDF @TH3(R1),AC1 ;AC1 ← THETA3
ADDF AC1,AC0 ;AC0 ← THETA2+THETA3
JSR PC,SNCOS ;FIGURE OUT SIN & COS OF (THETA2 + THETA3)
STF AC0,S23 ;S23 = SIN(THETA2+THETA3)
STF AC1,C23
RTS PC ;THAT'S IT
; [CONTINUATION OF PUMUPD: GETN]
; Calculate the N vector of the Cartesian solution.
GETN: LDF C5,AC0 ;AC0 ← C5
MULF C6,AC0 ;AC0 ← C5*C6
STF AC0,AC1 ;AC1 ← C5*C6
MULF C4,AC0 ;AC0 ← C4*C5*C6
STF AC0,C4C5C6 ;STORE IT
MULF SIN4,AC1 ;AC1 ← S4*C5*C6
STF AC1,S4C5C6 ;STORE IT
LDF SIN4,AC0 ;AC0 ← S4
MULF SIN6,AC0 ;AC0 ← S4*SIN6
STF AC0,S4S6
LDF SIN5,AC0 ;AC0 ← S5
MULF C6,AC0 ;AC0 ← S5*C6
STF AC0,S5C6 ;STORE IT
LDF C4,AC0 ;AC0 ← C4
MULF SIN6,AC0 ;AC0 ← C4*SIN6
STF AC0,C4S6
ADDF S4C5C6,AC0 ;AC0 ← S4*C5*C6 + C4*SIN6
STF AC0,PART2 ;STORE INTERMEDIATE RESULT
LDF C4C5C6,AC0 ;AC0 ← C4*C5*C6
SUBF S4S6,AC0 ;AC0 ← C4*C5*C6 - S4*SIN6
STF AC0,PART1A
MULF C23,AC0 ;AC0 ← C23*PART1A
LDF S23,AC1 ;AC1 ← S23
MULF S5C6,AC1 ;AC1 ← S23*S5*C6
SUBF AC1,AC0 ;AC0 ← C23*PART1A - S23*S5*C6
STF AC0,PART1 ;STORE INTERMEDIATE RESULT
JSR PC,GETXY ;USE PART1 & PART2 TO CALCULATE AC0←NX, AC1←NY
STF AC0,NX(R0) ;STORE NX
STF AC1,NY(R0) ;STORE NY
LDF PART1A,AC0 ;AC0 ← PART1A
MULF S23,AC0 ;AC0 ← S23*PART1A
LDF C23,AC1 ;AC1 ← C23
MULF S5C6,AC1 ;AC1 ← C23*S5*C6
ADDF AC1,AC0 ;AC0 ← S23*PART1A + C23*S5*C6
NEGF AC0 ;NEGATE RESULT ==> -S23*PART1A - C23*S5*C6
STF AC0,NZ(R0) ;STORE RESULT - THIS IS Nz.
RTS PC ;TO CALLER.
; [CONTINUATION OF PUMUPD: GETO]
; Calculate the O vector of the Cartesian solution.
GETO: LDF C5,AC0 ;AC0 ← C5
MULF SIN6,AC0 ;AC0 ← C5*SIN6
STF AC0,AC1 ;AC1 ← C5*SIN6
MULF C4,AC0 ;AC0 ← C4*C5*SIN6
STF AC0,C4C5S6 ;STORE IT
MULF SIN4,AC1 ;AC1 ← S4*C5*SIN6
LDF C4,AC0 ;AC0 ← C4
MULF C6,AC0 ;AC0 ← C4*C6
SUBF AC1,AC0 ;AC0 ← -S4*C5*SIN6 + C4*C6
STF AC0,PART2 ;STORE HALF THE RESULT
LDF SIN5,AC0 ;AC0 ← S5
MULF SIN6,AC0 ;AC0 ← S5*SIN6
STF AC0,S5S6 ;STORE IT
MULF S23,AC0 ;AC0 ← S23*S5*SIN6
STF AC0,PART1B ;STORE IT
LDF SIN4,AC0 ;AC0 ← S4
MULF C6,AC0 ;AC0 ← S4*C6
ADDF C4C5S6,AC0 ;AC0 ← C4*C5*SIN6 + S4*C6
STF AC0,PART1A ;STORE IT
MULF C23,AC0 ;AC0 ← C23*PART1A
NEGF AC0 ;AC0 ← -C23*PART1A
ADDF PART1B,AC0 ;AC0 ← -C23*PART1A + PART1B
STF AC0,PART1 ;STORE OTHER HALF OF RESULT
JSR PC,GETXY ;PUT X & Y COMPONENTS IN AC0 & AC1.
STF AC0,OX(R0) ;STORE X COMPONENT
STF AC1,OY(R0) ;STORE Y COMPONENT
LDF PART1A,AC0 ;AC0 ← PART1A
MULF S23,AC0 ;AC0 ← S23*PART1A
LDF C23,AC1 ;AC1 ← C23
MULF S5S6,AC1 ;AC1 ← C23*S5*SIN6
ADDF AC1,AC0 ;AC0 ← S23*PART1A + C23*S5*SIN6
STF AC0,OZ(R0) ;STORE Z COMPONENT OF O VECTOR
RTS PC ;RETURN
; [CONTINUATION OF PUMUPD: GETA]
; Calculate the A vector of the Cartesian solution.
GETA: LDF C4,AC0 ;AC0 ← C4
MULF SIN5,AC0 ;AC0 ← C4*S5
STF AC0,C4S5 ;STORE IT
LDF SIN4,AC1 ;AC1 ← S4
MULF SIN5,AC1 ;AC1 ← S4*S5
STF AC1,PART2 ;THIS IS HALF THE RESULT
MULF C23,AC0 ;AC0 ← C23*C4*S5
LDF S23,AC1 ;AC1 ← S23
MULF C5,AC1 ;AC1 ← S23*C5
ADDF AC1,AC0 ;AC0 ← C23*C4*S5 + S23*C5
STF AC0,PART1 ;THIS IS THE OTHER HALF
JSR PC,GETXY ;PUT X & Y COMPONENTS IN AC0 & AC1.
STF AC0,AX(R0) ;STORE X COMPONENT
STF AC1,AY(R0) ;AND Y COMPONENT
LDF C23,AC0 ;AC0 ← C23
MULF C5,AC0 ;AC0 ← C23*C5
LDF S23,AC1 ;AC1 ← S23
MULF C4S5,AC1 ;AC1 ← S23*C4*S5
SUBF AC1,AC0 ;AC0 ← -S23*C4*S5 + C23*C5
STF AC0,AZ(R0) ;STORE Z COMPONENT OF A VECTOR
RTS PC
; [CONTINUATION OF PUMUPD: GETP]
; Calculate the P vector of the Cartesian solution.
GETP: LDF D4,AC0 ;AC0 ← D4
MULF S23,AC0 ;AC0 ← D4*S23
LDF A3,AC1 ;AC1 ← A3
MULF C23,AC1 ;AC1 ← A3*C23
ADDF AC1,AC0 ;AC0 ← D4*S23 + A3*C23
LDF A2,AC1 ;AC1 ← A2
MULF COS2,AC1 ;AC1 ← A2*C2
ADDF AC1,AC0 ;AC0 ← D4*S23 + A3*C23 + A2*C2
STF AC0,PART1 ;THIS IS PART OF THE RESULT
MOV D3,PART2 ;SET PART2 ← D3. MOVE 1ST WORD
MOV D3+2,PART2+2 ; AND 2ND WORD.
JSR PC,GETXY ;GET X & Y COMPONENTS, STORE IN AC0 & AC1.
STF AC0,PX(R0) ;STORE X & Y COMPONENTS NOW
STF AC1,PY(R0)
LDF D4,AC0 ;NOW CALCULATE PZ. AC0 ← D4
MULF C23,AC0 ;AC0 ← D4*C23
LDF A3,AC1 ;AC1 ← A3
MULF S23,AC1 ;AC1 ← A3*S23
SUBF AC1,AC0 ;AC0 ← D4*C23 - A3*S23
LDF A2,AC1 ;AC1 ← A2
MULF SIN2,AC1 ;AC1 ← A2*SIN2
SUBF AC1,AC0 ;AC0 ← D4*C23 - A3*S23 - A2*S2
STF AC0,PZ(R0) ;STORE PZ IN RESULT MATRIX
RTS PC
; [CONTINUATION OF PUMUPD: GETXY]
; Support routine.
GETXY: LDF PART1,AC0 ;AC0 ← PART1
MULF COS1,AC0 ;AC0 ← C1*PART1
LDF PART2,AC1 ;AC1 ← PART2
MULF SIN1,AC1 ;AC1 ← SIN1*PART2
SUBF AC1,AC0 ;AC0 ← C1*PART1 - SIN1*PART2
LDF PART1,AC1 ;AC1 ← PART1
MULF SIN1,AC1 ;AC1 ← SIN1*PART1
LDF PART2,AC2 ;AC2 ← PART2
MULF COS1,AC2 ;AC2 ← C1*PART2
ADDF AC2,AC1 ;AC1 ← SIN1*PART1 + C1*PART2
RTS PC
; [CONTINUATION OF PUMUPD: OFSETW]
; Account for the length of the tool by offsetting the result by an amount
; equal to the tool length times the A vector (which is a unit vector).
; For both arms, account for the offset of the origin of the PUMA's
; world, as described in PUMSOL.
; For the Green arm, account for the rotation of the PUMA's world
; by negating the X and Y components of the direction vectors.
; Green transformation: (x,y,z) → (x0-x, y0-y, z0+z).
; Red transformation: (x,y,z) → (x0+x, y0+y, z0+z).
OFSETW: LDF AX(R0),AC0 ;AC0 ← AX
MULF TOOLEN,AC0 ;AC0 ← AX*TOOLLENGTH
ADDF PX(R0),AC0 ;AC0 ← PX + AX*TOOLLENGTH
CMP R5,#GCON ;IS IT THE GREEN ARM? IF SO,
BNE 5$ ;THEN CONTINUE AND NEGATE PX
NEGF AC0 ;NOW OFFSET THE ORIGIN: GET -PX
5$: ADDF XCOORD(R5),AC0 ;FIND +-X + X0
STF AC0,PX(R0) ;THIS IS OFFSET PX
LDF AY(R0),AC0 ;AC0 ← AY
MULF TOOLEN,AC0 ;AC0 ← AY*TOOLLENGTH
ADDF PY(R0),AC0 ;AC0 ← PY + AY*TOOLLENGTH
CMP R5,#GCON ;GREEN ARM?
BNE 10$
NEGF AC0 ;ACCOUNT FOR OFFSET ORIGIN
10$: ADDF YCOORD(R5),AC0
STF AC0,PY(R0) ;THIS IS OFFSET PY
LDF AZ(R0),AC0 ;AC0 ← AZ
MULF TOOLEN,AC0 ;AC0 ← AZ*TOOLLENGTH
ADDF PZ(R0),AC0 ;AC0 ← PZ + AZ*TOOLLENGTH
ADDF ZCOORD(R5),AC0 ;NOW OFFSET TO ORIGIN
STF AC0,PZ(R0) ;THIS IS OFFSET PZ
CMP R5,#GCON ;GREEN ARM?
BNE 20$
NEGF NX(R0) ;NEGATE THE N VECTOR
NEGF NY(R0)
NEGF OX(R0) ;NEGATE THE O VECTOR
NEGF OY(R0)
NEGF AX(R0) ;NEGATE THE Z VECTOR
NEGF AY(R0)
20$: RTS PC
; [CONTINUATION OF PUMUPD: LOCAL DATA AND CONSTANTS]
DATA
C4C5C6: .BLKW 2 ;INTERMEDIATE RESULTS
S4C5C6: .BLKW 2
S5C6: .BLKW 2
S4S6: .BLKW 2
C4S6: .BLKW 2
C5S6: .BLKW 2
S5S6: .BLKW 2
C4C5S6: .BLKW 2
C4S5: .BLKW 2
ANG2T1: .BLKW 2
ANG2T2: .BLKW 2
PART1A: .BLKW 2
PART1B: .BLKW 2
EXACT: .WORD 0 ;0 means find nearest Puma solution,
;1 means get nearest sol'n based on where arm
;currently is. I.e. preserve left/right arm
;configuration.
CODE
;JACOB - COMPUTES JACOBIAN MATRIX
;COMPUTES JACOBIAN MATRIX FOR A ARBITRARY TRANSFORMATIION.
;
; WE NEED:
; 1. PTR TO STORAGE FOR JACOBIAN MATRIX
; 2. PTR TO TABLE OF PTRS TO JOINT ANGLES
; 3. PTR TO ORC OR 6RC MATRIX
; 4. BLUE/YELLOW INDICATOR
; 5. ORC OR 6RC INDICATOR
; 6. STORAGE FOR CA6, CA3, CA0?
; R0 ← PTR TO FORCE TRANSFORMATION: C
; R1 ← PTR TO TABLE OF PTRS TO JOINT ANGLES
; R2 ← ARM/TABLE/HAND BITS
; R3 ← PTR TO ARRAY TO RETURN JACOBIAN IN
;ON COMPLETION
; T0 ← CT0 T3 ← CT3 T6 ← CT6
;EXECUTION TIME: 4 MSEC
;REGISTERS USED:
; R0,R1,R2,R3 PASS ARGUMENTS AND R0,R1 ARE GARBAGED
; ["JACOB" - FORM CT0,CT3,CT6]
JACOB: MOV R5,-(SP) ;SAVE REGISTERS
MOV R4,-(SP)
MOV R3,-(SP) ;RETURN JACOBIAN IN HERE
MOV R2,-(SP)
MOV #YCON,R3 ;ADDR OF YELLOW ARM PHYSICAL CONSTANTS
BIT #YELARM,R2 ;CHECK IF YELLOW OR BLUE ARM
BNE 1$ ;SKIP IF YELLOW ARM
MOV #BCON,R3 ;ELSE GET ADDR OF BLUE ARM CONSTANTS
ADD #14.,R1 ;POINT TO BLUE ARM JOINT ANGLES
1$: MOV S1+2(R3),-(SP) ;SAVE S1
MOV S1(R3),-(SP)
MOV R0,-(SP) ;SAVE C
BIT #FTABLE,R2 ;FORCE SENSING IN HAND OR TABLE COOR.
BNE 2$
;RELATIVE HAND TRANSFORMATION GIVEN:6TC, COMPUTE 3T0 AND 6T3
JSR PC,T6330 ;T3 ← 6T3 , T6 ← 3T0
MOV #T611,-(SP) ;T6 ← CT6 ← INVERSE(6TC)
MOV #T011,-(SP) ;T0 ← CT0 ← CT3*3T0
BR GET036
;TABLE TRANSFORMATION GIVEN:0TC, COMPUTE 0T3 AND 3T6
2$: MOV #10,R4 ;T3 ← 0T3 , T6 ← 3T6
JSR PC,T0336 ;DONT ADD IN BASEX OR BASEY
MOV #T011,-(SP) ;T0 ← CT0 ← INVERSE(0TC)
MOV #T611,-(SP) ;T6 ← CT6 ← CT3*3T6
;COMPUTE T0←CT0, T3←CT3, T6←CT6
GET036: MOV R0,R1 ;C
; MOV #T311,R0 ;T3←C*T3 *K
; MOV #T311,R2 ;T3 *K
; JSR PC,MATMUL ; *K
;REMOVE FROM HERE TO
MOV #T312,R0 ;T3 ← CT3 ← C*T3
MOV #T312,R2 ;FORM COL 2,3,4 OF NEW T3
MOV #3,R3
JSR PC,MULROW
MOV #T311,R0 ;COMPUTE T3(I,1) BY CROSSING T3(I,2)
MOV #T312,R1 ; WITH T3(I,3)
MOV #T313,R2
JSR PC,CROSS
;TO HERE
MOV (SP)+,R0 ;(R0) ← T3*T6
MOV #T311,R1
MOV #T611,R2
JSR PC,MATMUL
MOV (SP)+,R0 ;(R0) ← INVERSE(C)
MOV (SP)+,R1 ;C
; JSR PC,INVERT ; *K
;REMOVE FROM HERE
MOV #3,R2
1$: MOV (R1)+,(R0)+ ;TRANSPOSE A COL INTO A ROW
MOV (R1)+,(R0)+
MOV (R1)+,10(R0)
MOV (R1)+,12(R0)
MOV (R1)+,24(R0)
MOV (R1)+,26(R0)
SOB R2,1$
ADD #30,R0
CLRF (R0)+ ;X,Y,Z ← 0
CLRF (R0)+
CLRF (R0)
;TO HERE
; ["JACOB" - POSITION VECTORS, AXES OF ROTATION]
;COMPUTE POSITION VECTORS FROM AXES OF ROTATION TO HAND AND DIRECTION
;COSINES OF AXES OF ROTATION, ALL IN COORDINATE SYSTEM C
FRMJAC: LDF (SP)+,AC3 ;NEED S1 TO DETERMINE A POINT ON Z2
MOV 2(SP),R5 ;SAVE JACOBIAN IN HERE
MOV #T614,R0 ;CPX6
MOV #T014,R1 ;CPX0
MOV #T013,R2 ;CAX0
MOV #3,R3
1$: LDF (R0)+,AC0 ;POSITION VECTOR FOR JT 1: P1 ← CP6-CP0
SUBF (R1)+,AC0
STF AC0,(R5)+
LDF (R2),AC1 ; " " " JT 2: P2 ← P1-S1*CA0
MULF AC3,AC1
MOV (R2)+,10(R5) ;ROTATION AXIS OF JT 1: Z1 ← CA0
MOV (R2)+,12(R5)
SUBF AC1,AC0
STF AC0,24(R5)
SOB R3,1$
ADD #30,R5 ;STORE ROTATION AXIS OF JT 2 HERE: Z2
MOV #T311,R0 ;Z2 ← -CT3 ( 1ST COLUMN OF MATRIX CT3 )
MOV #T313,R1 ;JT 3 JACOBIAN HAS ONLY A FORCE COMPONENT: CA3
MOV #3,R2
2$: LDF (R0)+,AC0 ;Z2 ← -CT3
NEGF AC0
STF AC0,(R5)+
LDF (R1)+,AC0 ;CA3
STF AC0,10(R5)
CLRF 24(R5) ;CONTRIBUTION OF JT3 TO ROTATIONS: Z3 ← 0
SOB R2,2$
ADD #30,R5 ;TEMPORARILY SAVE POSITION VECTOR JT 4 IN HERE
MOV #T614,R0 ;CPX6
MOV #T314,R1 ;CPX3
MOV #T313,R2 ;CAX3
MOV #3,R3
3$: LDF (R0)+,AC0 ;POSITION VECTOR FOR JT 4: P4 ← CP6-CP3
SUBF (R1)+,AC0
MOV (R2)+,14(R5) ;ROTATION AXIS OF JT 4: Z4 ← CA3
MOV (R2)+,16(R5)
STF AC0,(R5)+
STF AC0,24(R5) ;POSITION VECTOR FOR JT 5: P5 ← P4
SOB R3,3$
ADD #30,R5 ;PUT DIRECTION COSINES OF Z5 IN HERE
LDF SINT6,AC2 ;NEED SIN/COS THETA 6
LDF COST6,AC3
MOV #T611,R0 ;1ST COL OF CT6
MOV #T612,R1 ;2ND " " "
MOV #T613,R2 ;CAX6
MOV #3,R3
4$: LDF (R0)+,AC0 ;COMPONENT OF Z5 ← T6I1*ST6+T6I2*CT6
MULF AC2,AC0
; MOV 14(R2),14(R5) ;POSITION VECTOR OF JT6: P6 ← CP6 *K
; MOV 16(R2),16(R5) ; *K
CLR 14(R5) ;POSITION VECTOR FOR JT6: P6 ← 0
CLR 16(R5)
LDF (R1)+,AC1
MULF AC3,AC1
MOV (R2)+,30(R5) ;ROTATION AXIS OF JT 6: Z6 ← CAX6
MOV (R2)+,32(R5)
ADDF AC1,AC0
STF AC0,(R5)+
SOB R3,4$
; ["JACOB" - CROSS PRODUCTS, CLEAN UP]
;COMPUTE COMPONENTS OF LINEAR MOTION BY TAKING CROSS PRODUCTS. NOTE
;THAT JOINT 6 DOES NOT CONTRIBUTE TO LINEAR MOTION AND JOINT 3 NEEDS
;NO CROSS PRODUCT SINCE IT IS A PRISMATIC JOINT.
CROSSS: MOV R5,R0 ;POSITION COMPONENTS JT 1: Z1 X P1
SUB #170,R0 ;1ST ROW, 1ST COL OF JACOBIAN
MOV R0,R1
ADD #14,R1 ;Z1
MOV R0,R2 ;P1
JSR PC,CROSS
ADD #20,R0 ;POSITION COMPONENTS JT 2: Z2 X P2
ADD #20,R1 ;Z2
ADD #20,R2 ;P2
JSR PC,CROSS
ADD #50,R0 ;POSITION COMPONENTS JT 4: Z4 X P4
ADD #50,R1 ;Z4
ADD #50,R2 ;P2
JSR PC,CROSS
ADD #20,R0 ;POSITION COMPONENTS JT 5: Z5 X P5
ADD #20,R1 ;Z5
ADD #20,R2 ;P5
JSR PC,CROSS
;RESTORE REGISTERS AND EXIT
MOV (SP)+,R2 ;RESTORE REGISTERS
MOV (SP)+,R3
MOV (SP)+,R4
MOV (SP)+,R5
RTS PC ;EXIT
;END OF "JACOB"
;T0336 - COMPUTES TRANSFORMATION MATRICIES FOR JTS 1-3 AND 4-6
;"T0336" COMPUTES THE TRANSFORMATION MATRIX FROM THE BASE SYSTEM (0)
;TO THE END OF JOINT 3 AND THE MATRIX FROM THE COORDINATE SYSTEM OF
;JOINT 3 TO THE END OF JOINT 6. ON COMPLETION, THE MATRIX FROM 0 TO 3
;WILL BE STORED IN THE ARRAY "T3" AND THE MATRIX FROM 3 TO 6 WILL
;BE STORED IN "T6". IF R4 IS 0 THE X,Y LOCATION OF THE BASE OF THE
;ARM WILL BE ADDED IN, OTHERWISE R4 SHOULD BE SET TO '10
T0336U: MOV #T36PTU,R2 ;TABLE OF PTRS TO T0_3&T3_6
BR .+6
T0336: MOV #T36PTR,R2 ;TABLE OF POINTERS TO T0_3&T3_6
JSR PC,R03 ;CONSTRUCT UPPER LEFT 3x3 OF T0_3
LDF @(R1)+,AC0 ;T0_3(3,4)=CS2*S3+S1
MULF AC0,CS2
ADDF (R3)+,AC1 ;GET S1
STF AC1,T334
MULF AC0,AC2 ;T0_3(1,4)=CS1*SN2*S3-SN1*S2
MULF AC0,AC3 ;T0_3(2,4)=SN1*SN2*S3+CS1*S2
LDF (R3)+,AC1 ;GET S2
STF AC1,AC0
MULF SN1,AC0
ADD R4,R3 ;SKIP BASEX & BASEY IF REQUESTED
TST R4
BNE .+4
ADDF (R3)+,AC2 ;+ BASEX
SUBF AC0,AC2
STF AC2,T314
MULF CS1,AC1
TST R4
BNE .+4
ADDF (R3)+,AC3 ;+ BASEY
ADDF AC1,AC3
STF AC3,T324
JSR PC,R36 ;CONSTRUCT UPPER LEFT 3x3 OF T3_6
STF AC0,AC1 ;T3_6(3,4)=CS5*S6
MULF CS5,AC1
STF AC1,@(R2)+
STF AC0,AC1 ;T3_6(2,4)=SN4*ST5*SIN6
MULF @(R2)+,AC1
STF AC1,@(R2)+
MULF @(R2)+,AC0 ;T3_6(1,4)=CS4*ST5*S6
STF AC0,@(R2)
RTS PC
;END OF "T0336"
;T6330 - COMPUTES TRANSFORMATION MATRICIES FOR JTS 6-4 AND 3-0
;"T6330" COMPUTES THE INVERSE TRANSFORMATION MATRICIES FROM THOSE
;COMPUTED BY "T0336". ON COMPLETION, THE MATRIX FROM JOINT 6 TO 3
;IS STORED IN "T3" AND THE MATRIX FROM 3 TO 0 IS STORED IN "T6".
;NOTE THAT THE CORRECTIONS FOR THE X-Y LOCATION OF THE BASE OF
;THE ARMS IS NOT ADDED INTO THE MATRIX TRANSFORMATIONS.
T6330: MOV #T63PTR,R2 ;TABLE OF POINTERS TO T3_0&T6_3
JSR PC,R03 ;CONSTRUCT UPPER LEFT 3X3 OF T3_0
LDF (R3)+,AC2 ;T3_0(2,4)=SN2*S1
MULF AC2,SN2
MOV (R3)+,T614 ;T3_0(1,4)=S2
STF SN2,T624
MULF AC2,CS2 ;T3_0(3,4)=-CS2*S1-S3
MOV (R3),T614+2
ADDF @(R1)+,CS2
ADD #12,R3 ;DONT ADD IN BASEX & BASEY
NEGF CS2
STF CS2,T634
JSR PC,R36 ;CONSTRUCT UPPER LEFT 3X3 OF T6_3
CLRF T314 ;T6_3(1,4)=0
CLRF T324 ;T6_3(2,4)=0
NEGF AC0 ;T6_3(3,4)=-S6
STF AC0,T334
RTS PC
;END OF "T6330"
;R03 - COMPUTES ROTATION MATRIX FOR TRANSFORMATION FROM JTS 1-3
;ON COMPLETION, THIS ROUTINE WILL HAVE STORED THE ELEMENTS OF R0_3(1:3,1:3)
;INTO THE ARRAY POINTED TO BY R2. IN ADDITION, THE FLOATING POINT REGISTERS
;WILL CONTAIN THE FOLLOWING VALUES:
;
; AC0= SN2 AC1= CS2 AC2= CS1*SN2
; AC3= SN1*SN2 AC4= SN1 AC5= CS1
R03: LDF @(R1)+,AC0 ;COMPUTE SIN/COS THETA 1
JSR PC,SNCOS
STF SN,@(R2)+ ;T0_3(1,1)=SN1
STF CS,@(R2)+ ;T0_3(2,1)=-CS1
STF SN,SN1 ;AND SAVE FOR LATER
STF CS,CS1
LDF @(R1)+,AC0 ;COMPUTE SIN/COS THETA 2
JSR PC,SNCOS
STF SN,@(R2)+ ;T0_3(3,2)=-SN2
STF CS2,@(R2)+ ;T0_3(3,3)=CS2
STF CS2,AC2 ;T0_3(1,2)=CS1*CS2
MULF CS1,AC2
ADD #100000,@-6(R2) ;CORRECT SIGN( T0_3(2,1) )
STF AC2,@(R2)+
STF CS2,AC2 ;T0_3(2,2)=SN1*CS2
MULF SN1,AC2
ADD #100000,@-6(R2) ;CORRECT SIGN( T0_3(3,2) )
STF AC2,@(R2)+
LDF SN2,AC2 ;T0_3(1,3)=CS1*SN2
MULF CS1,AC2
STF AC2,@(R2)+
LDF SN1,AC3 ;T0_3(2,3)=SN1*SN2
MULF SN2,AC3
STF AC3,@(R2)+
CLRF @(R2)+ ;T0_3(3,1)=0
RTS PC
;END OF "R03"
;R36 - COMPUTES ROTATION MATRIX FOR TRANSFORMATION FROM JTS 4-6
;ON COMPLETION, THIS ROUTINE WILL HAVE STORED THE ELEMENTS OF R3_6(1:3,1:3)
;INTO THE ARRAY POINTED TO BY R2. SINCE THE ELEMENT R3_6(1:1) IS NEVER
;NEED BY ANY OF THE CALLING ROUTINES, THIS IS THE ONLY MATRIX ELEMENT THAT
;IS NOT COMPUTED. AT THE COMPLETION OF THIS ROUTINE, THE FLOATING POINT
;REGISTERS CONTAIN THE FOLLOWING VALUES:
; AC0= S6 AC5= CS5
R36: LDF @(R1)+,AC0 ;COMPUTE SIN/COS THETA 4
JSR PC,SNCOS
STF SN,-(SP) ;SAVE SIN/COS
STF CS,CS4
LDF @(R1)+,AC0 ;COMPUTE SIN/COS THETA 5
JSR PC,SNCOS
STF CS,@(R2)+ ;T3_6(3,3)=CS5
STF SN,AC2 ;T3_6(2,3)=SN4*ST5
MULF (SP),AC2
STF AC2,@(R2)+
STF SN,AC2 ;T3_6(1,3)=CS4*ST5
MULF CS4,AC2
STF AC2,@(R2)+
STF SN,-(SP) ;SAVE SIN/COS THETA 5
STF CS,CS5
LDF @(R1)+,AC0 ;COMPUTE SIN/COS THETA 6
JSR PC,SNCOS
STF SN,SINT6 ;JACOB NEEDS THESE
STF CS,COST6
LDF (SP)+,AC2 ;T3_6(3,2)=ST5*ST6
STF AC2,AC3
MULF SN,AC2
STF AC2,@(R2)+
MULF CS,AC3 ;T3_6(3,1)=-ST5*CT6
STF AC3,@(R2)
LDF (SP)+,AC2 ;NEED COMBINATIONS OF SIN/COS T4&T6
STF AC2,AC3
MULF SN,AC2 ;SN4*ST6
ADD #100000,@(R2)+ ;COMPLEMENT T3_6(3,1)
MULF CS,SN4 ;SN4*CT6
MULF CS4,SN ;CS4*ST6
MULF CS4,CS ;CS4*CT6
MULF CS5,AC2 ;T3_6(2,2)=-SN4*CS5*ST6+CS4*CT6
SUBF AC1,AC2
STF AC2,@(R2)
STF AC3,AC2 ;T3_6(2,1)=SN4*CS5*CT6+CS4*ST6
MULF CS5,AC2
ADD #100000,@(R2)+ ;COMPLEMENT T3_6(2,2)
ADDF AC0,AC2
STF AC2,@(R2)+
MULF CS5,AC0 ;T3_6(1,2)=-SN4*CT6-CS4*CS5*ST6
ADDF AC3,AC0
NEGF AC0
STF AC0,@(R2)+
LDF (R3)+,AC0 ;NEXT ROUTINE NEEDS S6
RTS PC
;END OF "R36"
;INVERT - INVERTS A TRANSFORMATION STORED BY COLUMNS
;
; R0 ← PTR TO STORAGE FOR INVERTED TRANSFORMATION
; R1 ← PTR TO TRANSFORMATION TO BE INVERTED
;
INVERT: MOV #3,R2 ;COUNTER
LDF 44.(R1),AC0
STF AC0,AC4
LDF 40.(R1),AC3
LDF 36.(R1),AC2
1$: LDF (R1)+,AC0 ;NEW T(I,4) ← -OLD T(J,I)*T(J,4)
STF AC0,(R0)
MULF AC2,AC0
ADD #12.,R0
LDF (R1)+,AC1
STF AC1,(R0)
MULF AC3,AC1
ADD #12.,R0
ADDF AC1,AC0
LDF (R1)+,AC1
STF AC1,(R0)
MULF AC4,AC1
SUB #20.,R0
ADDF AC1,AC0
NEGF AC0
STF AC0,32.(R0)
SOB R2,1$
RTS PC
;END OF "INVERT"
;MATMUL - PERFORMS THE OPERATION T0 ← T1*T2
;WON'T WORK IF LOC(T0) = LOC(T1)
;
; R0 ← PTR TO ARRAY FOR RESULT: T0
; R1 ← PTR TO T1
; R2 ← PTR TO T2
MATMUL: JSR PC,MULSHR ;FORM COL 2,3,4
SUB #36.,R0 ;COMPUTE T1(I,1) BY CROSSING T1(I,2)
MOV R0,R1 ; WITH T1(I,3)
ADD #12.,R1
MOV R1,R2
ADD #12.,R2
JSR PC,CROSS
RTS PC
MULROT: ADD #12.,R0 ;FORM COL 1,2,3,4 OF TRANS X ROTATION TRANS
ADD #12.,R2
MOV #2,R3
JSR PC,MULCOL
ADD #36.,R1 ;LAST ROW OF T0 = T1
LDF (R1)+,AC0
STF AC0,(R0)+
LDF (R1)+,AC0
STF AC0,(R0)+
LDF (R1),AC0
STF AC0,(R0)
SUB #44.,R0 ;COMPUTE T1(I,1) BY CROSSING T1(I,2)
MOV R0,R1 ; WITH T1(I,3)
ADD #12.,R1
MOV R1,R2
ADD #12.,R2
JSR PC,CROSS
RTS PC
MULSHR: ADD #12.,R0 ;FORM COL 2,3,4 OF TRANS X TRANS
ADD #12.,R2
MOV #3,R3
JSR PC,MULCOL
ADD #44.,R1 ;ADD IN T1(I,4)
ADDF (R1),AC0
STF AC0,-(R0)
LDF -(R0),AC0
ADDF -(R1),AC0
STF AC0,(R0)
LDF -(R0),AC0
ADDF -(R1),AC0
STF AC0,(R0)
RTS PC
MULR: JSR PC,MULRSH ;FORM COL 1,2,3 OF TRANS X TRANS
SUB #36.,R0 ;COMPUTE T1(I,1) BY CROSSING T1(I,2)
MOV R0,R1 ; WITH T1(I,3)
ADD #12.,R1
MOV R1,R2
ADD #12.,R2
JSR PC,CROSS
RTS PC
MULRSH: ADD #12.,R0 ;FORM COL 2,3 OF TRANS X TRANS
ADD #12.,R2
MOV #2,R3
JSR PC,MULCOL
RTS PC
;END OF "MATMUL"
;MULT - PERFORMS THE OPERATION A0 ← A1*A2
;WILL NOT WORK FOR THE CASE OF LOC(A0)=LOC(A1)
;
; R0 ← PTR TO ARRAY FOR RESULT: A0
; R1 ← PTR TO 3X3 MATRIX: A1
; R2 ← PTR TO ARRAY A2
; R3 ← NUMBER OF COLUMNS IN A0,A2
;
;AT THE END OF THE OPERATION R0,R2 ARE LEFT POINTING AT
;THE FIRST ELEMENT IN THE N+1 COLUMN
;AND AC0 CONTAINS THE LAST SUM. R1 IS LEFT UNCHANGED
MULROW: MOV #BYROWS,R4
BR MULT
MULCOL: MOV #BYCOLS,R4
MULT: MOV #3,R5 ;MULT A2 BY 3 ROWS OF A1
LDF (R2)+,AC2 ;LOAD A COLUMN OF A2
LDF (R2)+,AC3
LDF (R2)+,AC0
STF AC0,AC4
1$: LDF (R1),AC0 ;A1(I,1)*A2(1,J)
MULF AC2,AC0
ADD (R4)+,R1
LDF (R1),AC1 ;+ A1(I,2)*A2(2,J)
MULF AC3,AC1
ADD (R4)+,R1
ADDF AC1,AC0
LDF (R1),AC1 ;+ A1(I,3)*A2(3,J)
MULF AC4,AC1
ADD (R4)+,R1
MOV (R4),R4
ADDF AC1,AC0
STF AC0,(R0)+ ;SAVE A0(I,J)
SOB R5,1$
SOB R3,MULT
RTS PC
DATA
BYCOLS: .WORD 14,14,-24,.+2
.WORD 14,14,-24,.+2
.WORD 14,14,-40,BYCOLS
BYROWS: .WORD 4,4,4,.+2
.WORD 4,4,4,.+2
.WORD 4,4,-40,BYROWS
CODE
;END OF "MULT"
;CROSS - VECTOR CROSS PRODUCT OPERATION V0 ← V1 X V2
; R0 ← PTR TO VECTOR FOR RESULT: V0
; R1 ← PTR TO VECTOR V1
; R2 ← PTR TO VECTOR V2
CROSS: LDF (R1)+,AC0 ;X1
LDF (R2)+,AC1 ;X2
LDF (R2)+,AC2 ;Y2
STF AC2,AC4
LDF (R1)+,AC3 ;Y1
STF AC3,AC5
MULF AC0,AC2 ;X1*Y2
MULF AC1,AC3 ;X2*Y1
SUBF AC3,AC2 ;Z0 = X1*Y2-X2*Y1
LDF (R2),AC3 ;Z2
MULF AC3,AC0 ;X1*Z2
MULF AC5,AC3 ;Y1*Z2
STF AC0,AC5
LDF (R1),AC0 ;Z1
MULF AC0,AC1 ;Z1*X2
MULF AC4,AC0 ;Z1*Y2
SUBF AC5,AC1 ;Y0 = Z1*X2-X1*Z2
SUBF AC0,AC3 ;X0 = Y1*Z2-Z1*Y2
STF AC3,(R0)+ ;SAVE X0,Y0,Z0
STF AC1,(R0)+
STF AC2,(R0)
RTS PC
;END OF "CROSS"
;LOCAL STORAGE AREA
DATA
T36PTU: .WORD T311,T321,T332,T333,T312,T322,T313,T323,T331
.WORD T033,T023,T013,T032,T031,T022,T021,T012,T034
.WORD T023,T024,T013,T014
T36PTR: .WORD T311,T321,T332,T333,T312,T322,T313,T323,T331
.WORD T633,T623,T613,T632,T631,T622,T621,T612,T634
.WORD T623,T624,T613,T614
T63PTR: .WORD T611,T612,T623,T633,T621,T622,T631,T632,T613
.WORD T333,T332,T331,T323,T313,T322,T312,T321
T011: .BLKW 2
T021: .BLKW 2
T031: .BLKW 2
T012: .BLKW 2
T022: .BLKW 2
T032: .BLKW 2
T013: .BLKW 2
T023: .BLKW 2
T033: .BLKW 2
T014: .BLKW 2
T024: .BLKW 2
T034: .BLKW 2
T311: .BLKW 2
T321: .BLKW 2
T331: .BLKW 2
T312: .BLKW 2
T322: .BLKW 2
T332: .BLKW 2
T313: .BLKW 2
T323: .BLKW 2
T333: .BLKW 2
T314: .BLKW 2
T324: .BLKW 2
T334: .BLKW 2
CT6:
T611: .BLKW 2
T621: .BLKW 2
T631: .BLKW 2
T612: .BLKW 2
T622: .BLKW 2
T632: .BLKW 2
T613: .BLKW 2
T623: .BLKW 2
T633: .BLKW 2
T614: .BLKW 2
T624: .BLKW 2
T634: .BLKW 2
SINT6: .BLKW 2 ;SIN THETA 6
COST6: .BLKW 2 ;COS THETA 6
;PHYSICAL CONSTANTS FOR YELLOW AND BLUE ARMS
;ADDRESSES OF ARM CONSTANTS RELATIVE TO THE START OF THE FOLLOWING TABLES
S1 ==0 ;JOINT 1 OFFSET
S2 ==4 ;JOINT 2 OFFSET
BASEX ==10 ;TABLE COORDINATES OF BASE OF ARM
BASEY ==14
S6 ==20 ;JOINT 6 OFFSET
S22 ==24 ;S2**2
STOP1 ==30 ;MIN. & MAX. JOINT STOPS RELATIVE TO START OF CONST. AREA
;JOINT 2 HAS NO STOP LIMIT SINCE ALL SOLUTIONS ARE POSSIBLE
STOP3 ==40
STOP4 ==50
STOP5 ==60
STOP6 ==70
MIDDY1==100 ;MID-RANGE OF MOTION
MIDDY4==104
; [YELLOW ARM TABLE OF CONSTANTS]
YCON: .FLT2 16.24 ;JOINT 1 OFFSET
.FLT2 6.05 ;JOINT 2 OFFSET
.FLT2 29.5 ;TABLE COORDINATES OF ARM BASE
.FLT2 8.375
.FLT2 9.38 ;JOINT 6 OFFSET
.FLT2 36.6025 ;S2**2
;YELLOW ARM JOINT STOP LIMITS
.FLT2 -185.0 ;JOINT 1 MIN
.FLT2 60.0 ; MAX
.FLT2 6.5 ;JOINT 3 MIN
.FLT2 27.5 ; MAX
.FLT2 -175.0 ;JOINT 4 MIN
.FLT2 86.0 ; MAX
.FLT2 -101.0 ;JOINT 5 MIN
.FLT2 101.0 ; MAX
.FLT2 -135.0 ;JOINT 6 MIN -290.0 WITH BOTH WIPERS WORKING
.FLT2 110.0 ; MAX
.FLT2 -62.5 ;MIDDY1
.FLT2 -44.5 ;MIDDY4
; [BLUE ARM TABLE OF CONSTANTS]
;CONSTANT PARAMETERS FOR BLUE ARM, **ORDERED LIST**
BCON: .FLT2 20.24 ;JOINT 1 OFFSET
.FLT2 -6.05 ;JOINT 2 OFFSET
.FLT2 29.53125 ;TABLE COORDINATES OF ARM BASE
.FLT2 50.805
.FLT2 10.28125 ;JOINT 6 OFFSET
.FLT2 36.6025 ;S2**2
;BLUE ARM JOINT STOP LIMITS
.FLT2 -45.0 ;JOINT 1 MIN
.FLT2 190.0 ; MAX
.FLT2 6.75 ;JOINT 3 MIN
.FLT2 33.0 ; MAX
.FLT2 -395.0 ;JOINT 4 MIN
.FLT2 205.0 ; MAX
.FLT2 -95.0 ;JOINT 5 MIN
.FLT2 95.0 ; MAX
.FLT2 -110.0 ;JOINT 6 MIN
.FLT2 200.0 ; MAX
.FLT2 72.5 ;MIDDY1
.FLT2 -95.0 ;MIDDY4
[GREEN & RED ARM TABLE OF CONSTANTS]
;THESE ARE THE LOCATIONS, IN AL'S TERMS, OF THE ORIGIN OF THE SPACE THAT
;THE PUMAS USE; IE IT IS THE LOCATION OF (0,0,0) OF THE PUMA.
GCON: .FLT2 84.0 ;X COORD OF BASE
.FLT2 52.0 ;Y COORD OF BASE
.FLT2 27.0 ;Z COORD OF BASE
RCON: .FLT2 84.0 ;X COORD
.FLT2 7.0 ;Y
.FLT2 27.0 ;Z
;PUMA CONSTANTS AND MISC. DATA FOR PUMA ROUTINES
; -- CONSTANTS --
A2: .FLT2 17.0 ;THIS IS A[2]
A3: .FLT2 0.0
D3: .FLT2 5.87 ;THIS IS D[3] IN WRITEUP
D4: .FLT2 17.0
TOOLEN: .FLT2 6.7 ;LENGTH OF TOOL
LOSTOP: .FLT2 -160.0, -223.0, -52.0, -2.5, -100.0, -266.0
HISTOP: .FLT2 160.0, 43.0, 232.0, 2.5, 100.0, 266.0
LOLIM: .FLT2 -180.0, -270.0, -90.0, -180.0, -180.0, -180.0
JT1EXA: .FLT2 5.0 ;Maximum difference in Jt1 to be called Exact.
JT2EXA: .FLT2 5.0 ;Maximum difference in Jt2 to be called Exact.
; -- WORK VARIABLES --
PART1: .BLKW 2
PART2: .BLKW 2
SIN1: .BLKW 2 ;SIN(THETA1)
COS1: .BLKW 2 ;COS(THETA1)
SIN2: .BLKW 2 ;SIN(THETA2)
COS2: .BLKW 2 ;COS(THETA2)
SIN3: .BLKW 2 ;SIN(THETA3)
C3: .BLKW 2 ;COS(THETA3)
SIN4: .BLKW 2 ;SIN(THETA4)
C4: .BLKW 2 ;COS(THETA4)
SIN5: .BLKW 2 ;SIN(THETA5)
C5: .BLKW 2 ;COS(THETA5)
SIN6: .BLKW 2 ;SIN(THETA6)
C6: .BLKW 2 ;COS(THETA6)
S23: .BLKW 2 ;SIN(THETA2+THETA3)
C23: .BLKW 2 ;COS(THETA2+THETA3)
; -- FLOATING POINT CONSTANTS --
FLT01: .FLT2 0.20 ;MODIFIED TO ACCOUNT FOR ROUNDING ERRORS.
FLT001: .FLT2 0.001
FLT1: .FLT2 1.0
FLT4: .FLT2 4.0
FLT90: .FLT2 90.0
FLT179: .FLT2 179.0 ;DITTO - ROUNDING ERRS
FLT180: .FLT2 180.0
FLM180: .FLT2 -180.0
FLT360: .FLT2 360.0
TINYNO: .FLT2 -0.0002
CODE